Создать тепловую карту из CSV-файла, используя numpy и matplotlib - как отображать отрицательные числа на оси - PullRequest
0 голосов
/ 07 апреля 2020

Я хотел бы получить тепловую карту из данных CSV, которые содержат отрицательные значения по оси x. Я скопировал код из этого поста в качестве отправной точки: предыдущий пост . Однако, когда я пробую это, это не отображает отрицательные значения х. На самом деле, с некоторыми наборами данных (как в примере) кажется, что они вообще не устанавливают правильные значения оси. Я не уверен, почему это так, поскольку ось, кажется, определена из данных CSV в коде. Я думал, что это может быть связано с dtype=np.int, но, похоже, это не так.

import numpy as np
import matplotlib.pyplot as plt

csv_file_path = '<FILE PATH>'


def get_xyz_from_csv_file_np(csv_file_path):
    '''
    get a grid of values from a csv file
    csv file format: x0,y0,z0
    '''

    x, y, z = np.loadtxt(csv_file_path, delimiter=',', dtype=np.int).T

    plt_z = np.zeros((y.max()+1, x.max()+1))
    plt_z[y, x] = z

    return plt_z


def draw_heatmap(plt_z):
    # Generate y and x values from the dimension lengths
    plt_y = np.arange(plt_z.shape[0])
    plt_x = np.arange(plt_z.shape[1])

    z_min = plt_z.min()
    z_max = plt_z.max() 

    plot_name = "plot"
    z_name = "Signal"

    color_map = plt.cm.rainbow 
    fig, ax = plt.subplots()
    cax = ax.pcolor(plt_x, plt_y, plt_z, cmap=color_map, vmin=z_min, vmax=z_max) 
    ax.set_xlim(plt_x.min(), plt_x.max())
    ax.set_ylim(plt_y.min(), plt_y.max())
    fig.colorbar(cax).set_label(z_name, rotation=270) 
    ax.set_title(plot_name)  
    ax.set_aspect('auto')
    plt.show()
    return figure
    figure = plt.gcf()
    plt.show()
    return figure   


if __name__ == "__main__":
    fname = 'temp.csv'
    # create_test_csv(fname)
    res = get_xyz_from_csv_file_np(csv_file_path)
    draw_heatmap(res)

Вывод, который я получаю, таков:

enter image description here

Пример файла данных представляет собой CSV с разделителями-запятыми с этими данными (x, y, z):

-2  -1  0
-2  0   10
-2  1   0
-1  -1  2
-1  0   5
-1  1   2
0   -1  0
0   0   0
0   1   10
1   -1  10
1   0   0
1   1   0
2   -1  10
2   0   0
2   1   10

Может ли кто-нибудь (1) исправить этот код, чтобы отрицательные значения могли отображаться оси правильны и (2) объясните мне, что я делаю неправильно.

Спасибо!

1 Ответ

1 голос
/ 07 апреля 2020

Код ниже сначала копирует файл .csv с массивом, а затем извлекает x, y и z. Чтобы знать размеры, нужно учитывать не только максимум, но и разницу между максимумом и минимумом. Массивы x и y интересны только для остальной части кода из-за их минимума и максимума.

Чтобы нарисовать карту тепла, требуется только plt_z, поскольку она уже имеет правильную форму , x и y могут использоваться для установки экстентов (то есть значений для осей x и y). plt.imshow() аналогична plt.pcolor(), но позволяет устанавливать экстенты в качестве параметра. Требуется origin='lower', потому что для многих форматов изображений источник находится сверху.

Чтобы иметь метки в центре ячеек, необходимо добавить дополнительное поле 0.5. Для отображения тиков в каждой целой позиции можно использовать MultipleLocator().

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import ticker

def get_xyz_from_csv_file_np():
    data = [[-2, -1, 0],
            [-2, 0, 10],
            [-2, 1, 0],
            [-1, -1, 2],
            [-1, 0, 5],
            [-1, 1, 2],
            [0, -1, 0],
            [0, 0, 0],
            [0, 1, 10],
            [1, -1, 10],
            [1, 0, 0],
            [1, 1, 0],
            [2, -1, 10],
            [2, 0, 0],
            [2, 1, 10]]
    data = np.array(data, dtype=np.int)
    x = data[:, 0]
    y = data[:, 1]
    z = data[:, 2]
    n = y.max() - y.min() + 1
    m = x.max() - x.min() + 1
    return x.reshape(n, m), y.reshape(n, m), z.reshape(n, m)

def draw_heatmap(plt_x, plt_y, plt_z):
    plot_name = "plot"
    z_name = "Signal"
    color_map = plt.cm.rainbow
    fig, ax = plt.subplots()
    cax = ax.imshow(plt_z, cmap=color_map,
                    extent=[plt_x.min() - 0.5, plt_x.max() + 0.5, plt_y.min() - 0.5, plt_y.max() + 0.5], origin='lower')
    fig.colorbar(cax).set_label(z_name, rotation=270)
    ax.set_title(plot_name)
    ax.set_aspect('auto')
    # optionally force to have ticks at every integer position
    ax.xaxis.set_major_locator(ticker.MultipleLocator(1))
    ax.yaxis.set_major_locator(ticker.MultipleLocator(1))
    plt.show()

x, y, z = get_xyz_from_csv_file_np()
draw_heatmap(x, y, z)

resulting plot

PS: В случае, если значения z имеют естественный порядок, было бы лучше не использовать rainbow colormap , а одну из 'Perceptually Uniform Sequential' colormaps ('viridis' , "плазма", "ад", "магма", "цивидис").

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...