【问题标题】:matplotlib get bitmap from a scatter plotmatplotlib 从散点图中获取位图
【发布时间】:2021-08-13 11:15:28
【问题描述】:

我有一些需要绘制的点的坐标,然后将绘图转换为黑白位图:

import matplotlib.pyplot as plt
import matplotlib.image as mpimg
from PIL import Image

plt.scatter(x,y)
plt.tight_layout()
fig1 = plt.gcf()
plt.show()

type(fig1)
matplotlib.figure.Figure

如何从这个图中获取黑白位图作为类似于这个的numpy数组:

side = 5
image = np.random.choice([0, 1], size=side*side,  p=[.1, .9])
image = image.reshape(side,side)
image = np.expand_dims(image, axis=-1)
print("image.shape: ",image.shape)
plt.imshow(image, cmap=plt.get_cmap('gray'))

image.shape:  (5, 5, 1)

print(image.reshape(side,side))

[[1 1 1 0 1]
 [1 1 1 1 1]
 [1 0 1 1 0]
 [1 1 1 1 0]
 [1 1 1 1 1]]

更新 1

我还需要将生成的位图作为一个 numpy 数组。如何获得?

如果我使用 Zephyr 给出的解决方案:

fig, ax = plt.subplots(figsize = (5,5))
ax.hist2d(x, y, cmap = 'Greys', cmin = 0, cmax = 1)
plt.show()

我得到的图像与散点图不同。它们应该是相似的:

【问题讨论】:

    标签: python numpy matplotlib bitmap scatter-plot


    【解决方案1】:

    您可以创建一个网格并使用它来定义地图,其中最近的点将是白色的。我尝试使用随机数据,范围 0 到 1:

    import matplotlib.pyplot as plt
    import numpy as np
    
    n_points = 10
    # create random coordinates
    x, y = np.random.rand(n_points,2).T
    fig, ax = plt.subplots()
    ax.scatter(x,y)
    ax.set_xlim([0,1])
    ax.set_ylim([0,1])
    ax.set_aspect(1.0)
    

    # create a grid
    grid_points = 10
    grid_x = np.linspace(0,1,grid_points)
    grid_y = grid_x.copy()
    
    # initiate array of ones (white)
    image = np.ones([grid_points, grid_points])
    for xp, yp in zip(x,y):
        # selecing the closest point in grid
        index_x = np.argmin(np.abs(xp - grid_x))
        index_y = np.argmin(np.abs(yp - grid_y))
        # setting to black
        image[index_x,index_y] = 0
        
    # you need to transpose it so x is represented
    # by the columns and y by the rows
    fig, ax = plt.subplots()
    ax.imshow(
        image.T,
        origin='lower',
        cmap=plt.get_cmap('gray'))
    

    请注意,最接近的可能并不总是好的。使用更精细的网格会变得更好。

    【讨论】:

    • 谢谢!为什么需要转置 X 和 Y?据我了解,X 是一列,Y 是行号。不是吗?
    • 你对情节是正确的,但对数组不正确。默认情况下,numpy 数组的第一个维度是行号,第二个维度是列号,就像在 C 中一样。可以在 Wikipedia article 中找到一些解释。
    【解决方案2】:

    首先,我在(x_min, x_max)(y_min, y_max)范围内生成随机的N点:

    np.random.seed(42)
    
    N = 10
    x_min = 0
    x_max = 40
    y_min = -20
    y_max = 20
    
    x = np.random.uniform(x_min, x_max, N)
    y = np.random.uniform(y_min, y_max, N)
    

    然后我准备:

    • (size, size) 维度的grid(位图)
    • 两个向量 x_gridy_gridsize + 1 点中重新采样 (x_min, x_max)(y_min, y_max),所以 size inverval:每个 grid 单元格有一个间隔
    size = 10
    grid = np.zeros((size, size))
    x_grid = np.linspace(x_min, x_max, size + 1)
    y_grid = np.linspace(y_min, y_max, size + 1)
    

    然后我循环遍历每个grid 单元格;在每次迭代中,我检查是否至少有 1 个点 (x, y) 保持在该单元格的范围内。如果是这样,我将grid的对应值设置为1

    for i in range(size):
        for j in range(size):
            for x_i, y_i in zip(x, y):
                if (x_grid[i] < x_i <= x_grid[i + 1]) and (y_grid[j] < y_i <= y_grid[j + 1]):
                    grid[i, j] = 1
                    break
    

    生成的 numpy 矩阵:

    [[0. 0. 0. 1. 0. 0. 0. 0. 0. 0.]
     [0. 1. 0. 0. 0. 0. 0. 0. 0. 0.]
     [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
     [1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
     [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
     [0. 0. 1. 0. 0. 0. 0. 0. 0. 0.]
     [0. 0. 0. 0. 1. 0. 0. 0. 0. 0.]
     [0. 0. 1. 0. 0. 0. 0. 0. 1. 0.]
     [0. 0. 0. 0. 0. 1. 0. 0. 0. 0.]
     [0. 0. 0. 0. 0. 0. 0. 0. 0. 1.]]
    

    完整代码

    import matplotlib.pyplot as plt
    import numpy as np
    
    np.random.seed(42)
    
    N = 10
    x_min = 0
    x_max = 40
    y_min = -20
    y_max = 20
    
    x = np.random.uniform(x_min, x_max, N)
    y = np.random.uniform(y_min, y_max, N)
    
    size = 10
    grid = np.zeros((size, size))
    x_grid = np.linspace(x_min, x_max, size + 1)
    y_grid = np.linspace(y_min, y_max, size + 1)
    
    for i in range(size):
        for j in range(size):
            for x_i, y_i in zip(x, y):
                if (x_grid[i] < x_i <= x_grid[i + 1]) and (y_grid[j] < y_i <= y_grid[j + 1]):
                    grid[i, j] = 1
                    break
    
    fig, ax = plt.subplots(1, 2, figsize = (10, 5))
    
    ax[0].scatter(x, y)
    ax[0].set_xlim(x_min, x_max)
    ax[0].set_ylim(y_min, y_max)
    ax[0].grid()
    ax[0].set_xticks(x_grid)
    ax[0].set_yticks(y_grid)
    
    ax[1].imshow(grid.T, cmap = 'Greys', extent = (x_min, x_max, y_min, y_max))
    ax[1].invert_yaxis()
    
    plt.show()
    

    注意

    请注意,在ax.imshow 中,您需要转置矩阵 (grid.T),然后反转 y 轴,以便能够将ax.imshowax.scatter 进行比较。
    如果你想让grid矩阵匹配ax.imshow,那么你需要逆时针旋转90°:

    grid = np.rot90(grid, k=1, axes=(0, 1))
    

    旋转grid,对应上图:

    [[0. 0. 0. 0. 0. 0. 0. 0. 0. 1.]
     [0. 0. 0. 0. 0. 0. 0. 1. 0. 0.]
     [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
     [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
     [0. 0. 0. 0. 0. 0. 0. 0. 1. 0.]
     [0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]
     [1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
     [0. 0. 0. 0. 0. 1. 0. 1. 0. 0.]
     [0. 1. 0. 0. 0. 0. 0. 0. 0. 0.]
     [0. 0. 0. 1. 0. 0. 0. 0. 0. 0.]]
    

    【讨论】:

    • 我还需要将生成的位图作为一个 numpy 数组。如何获得?
    猜你喜欢
    • 1970-01-01
    • 2020-07-22
    • 2013-06-29
    • 2020-12-17
    • 1970-01-01
    • 1970-01-01
    • 2016-01-19
    • 1970-01-01
    相关资源
    最近更新 更多