英文:
Plotting a Pandas DataFrame with RGB values and coordinates
问题
我有一个包含列 ["x", "y", "r", "g", "b"]
的 pandas DataFrame,其中 x 和 y 表示像素的坐标,r、g、b 表示其 RGB 值。行包含像素网格的每个坐标的条目,并且是唯一的。如何使用 matplotlib 的 imshow()
函数显示这个 DataFrame?这需要将数据重塑为形状为 (M, N, 3)
的数组。
我通常使用 plt.imshow(df.pivot(columns="x", index="y", values="i"), interpolation="nearest")
的方法只适用于灰度图像。将 ["r", "g", "b"]
作为值参数会产生一个带有多级索引的 DataFrame。然而,我无法将其转换为正确的图像。简单地调用 .reshape(M, N, 3)
会创建一个错误的图像。
我还想过使用 df["rgb"] = list(zip(df.r, df.g, df.b))
创建一个新列。然而,我不确定如何将结果元组转换为 ndarray 的新轴。
英文:
I have a pandas DataFrame with the columns ["x", "y", "r", "g", "b"]
where x and y denote the coordinates of a pixel and r, g, b denote its RGB value. The rows contain entries for each coordinate of a grid of pixels and are unique. How can I display this DataFrame using matplotlibs's imshow()
? This requires reshaping the data into a array of shape (M, N, 3)
.
My usual approach of using plt.imshow(df.pivot(columns="x", index="y", values="i"), interpolation="nearest")
does only work for greyscale images. Placing ["r", "g", "b"]
as the values argument yields a DataFrame with a MultiIndex as columns. However I fail to convert this into a correct image. Simply calling .reshape(M, N, 3)
creates a wrong image.
I also had the idea of creating a new column with df["rgb"] = list(zip(df.r, df.g, df.b))
However I'm not sure on how to convert the resulting tuples into a new axis for the ndarray.
答案1
得分: 5
有一种简单的方法可以做到这一点。首先,你需要确保DataFrame按照x和y值进行排序,可以使用df = df.sort_values(by=['x', 'y'])
。
接下来,你可以通过调用df[['r', 'g', 'b']]
来选择DataFrame中的r、g和b三列。然后,通过调用df[['r', 'g', 'b']].values
将这些值转换为一个numpy数组,该数组的形状为(M*N, 3)
,其中M和N分别是图像的宽度和高度。
现在,将该数组重新调整为形状为(M, N, 3)
的数组,就完成了操作。
df = df.sort_values(by=['x', 'y'])
values = df[['r', 'g', 'b']].values
image = values.reshape(df['x'].max() + 1, df['y'].max() + 1, 3)
这里假设DataFrame中的x和y值从0开始,因此在计算图像的维度时需要加1。如果x和y值从1开始,可以这样调整数组的形状:(df['x'].max(), df['y'].max(), 3)
。
根据你认为图像的x和y维度是什么,你可能需要在最后对数组进行转置。
英文:
There exists an easy way to do this. First, you make sure the DataFrame is sorted by x- and y-values using df = df.sort_values(by=['x', 'y'])
.
Next, you select only the three columns for r, g and b from the DataFrame by calling df[['r', 'g', 'b']]
. You convert the values into a numpy array by calling df[['r', 'g', 'b']].values
, which will return an array of the shape (M*N, 3)
, assuming that M
and N
are the width and height of your image.
Now, reshape that array into the shape (M, N, 3)
and you are done.
df = df.sort_values(by=['x', 'y'])
values = df[['r', 'g', 'b']].values
image = values.reshape(df['x'].max() + 1 , df['y'].max() + 1, 3)
I'm assuming here that your x and y values in the DataFrame start at 0, therefore I add 1 for the dimensions. If your x and y values start at 1, the reshaping can be done like this (df['x'].max(), df['y'].max(), 3)
.
Depending on what you consider the x and y dimensions of your image, you might have to transpose the array in the end.
答案2
得分: 3
假设有以下示例数据:
x y r g b
0 1 0 0 255 255
1 5 1 255 255 0
2 4 2 255 0 255
3 4 0 0 255 255
4 3 1 255 255 0
5 2 3 255 0 0
你可以使用以下代码:
N = df['x'].max()+1
M = df['y'].max()+1
tmp = (df.pivot(columns='x', index='y', values=['r', 'g', 'b'])
.reindex(index=range(M),
columns=pd.MultiIndex.from_product([['r', 'g', 'b'],
range(N)
]))
.sort_index(level=1, axis=1, sort_remaining=False)
.to_numpy().reshape((M, N, 3))
)
plt.imshow(tmp, interpolation='nearest')
输出结果如下图所示:
另外,如果你已经有了所有的 x 和 y 值:
np.random.seed(0)
M, N = 4, 5
df = pd.DataFrame({'x': np.repeat(np.arange(N), M),
'y': np.tile(np.arange(M), N),
'r': np.random.randint(0, 256, M*N),
'g': np.random.randint(0, 256, M*N),
'b': np.random.randint(0, 256, M*N),
})
tmp = (df[['x', 'y', 'r', 'g', 'b']]
.melt(['x', 'y'], var_name='color')
.assign(color=lambda d: pd.Categorical(d['color'],
categories=['r', 'g', 'b'],
ordered=True))
.sort_values(by=['y', 'x', 'color'])
['value'].to_numpy()
.reshape(M, N, 3)
)
plt.imshow(tmp, interpolation='nearest')
输出结果如下图所示:
英文:
Assuming this example:
x y r g b
0 1 0 0 255 255
1 5 1 255 255 0
2 4 2 255 0 255
3 4 0 0 255 255
4 3 1 255 255 0
5 2 3 255 0 0
You could use:
N = df['x'].max()+1
M = df['y'].max()+1
tmp = (df.pivot(columns='x', index='y', values=['r', 'g', 'b'])
.reindex(index=range(M),
columns=pd.MultiIndex.from_product([['r', 'g', 'b'],
range(N)
]))
.sort_index(level=1, axis=1, sort_remaining=False)
.to_numpy().reshape((M, N, 3))
)
plt.imshow(tmp, interpolation='nearest')
Output:
Alternatively, if you have all x/y:
np.random.seed(0)
M, N = 4, 5
df = pd.DataFrame({'x': np.repeat(np.arange(N), M),
'y': np.tile(np.arange(M), N),
'r': np.random.randint(0, 256, M*N),
'g': np.random.randint(0, 256, M*N),
'b': np.random.randint(0, 256, M*N),
})
tmp = (df[['x', 'y', 'r', 'g', 'b']]
.melt(['x', 'y'], var_name='color')
.assign(color=lambda d: pd.Categorical(d['color'],
categories=['r', 'g', 'b'],
ordered=True))
.sort_values(by=['y', 'x', 'color'])
['value'].to_numpy()
.reshape(M, N, 3)
)
plt.imshow(tmp, interpolation='nearest')
Output:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论