Сконфигурируйте цветовую панель matplotlib для соответствия значениям трехмерной поверхности - PullRequest
2 голосов
/ 13 мая 2019

Я пытаюсь отобразить результат быстрого преобразования Фурье в виде 3D-поверхности из 2D-матрицы (форма: 2048x1024) с цветной полосой на стороне, которая должна соответствовать моим значениям. Дисплей работает нормально, но «цвет» и цвет графика не совпадают. Как настроить цветовую панель и график для соответствия?

Я пытался установить значения vmin и vmax в соответствии с моими результатами FFT, но тогда цвет графика совершенно неправильный. Я также попробовал функцию clim(vmin, vmax) или метод .set_clim(vmin, vmax), но проблема все та же.

Вот мой код: rp - это матрица 2048x1024.

import numpy as np
from pylab import *
from mpl_toolkits.mplot3d import Axes3D


figure(2, figsize=(9.6, 7.2))
ax1 = gca(projection='3d')
X = np.arange(0, 1024)
Y = np.arange(0, 2048)
X, Y = np.meshgrid(X, Y)
Z = 20 * np.log10(abs(rp))
# Plot the surface.
surf1 = ax1.plot_surface(X, Y, Z, cmap='jet', antialiased=False, vmin=np.min(Z), vmax=np.max(Z))
# Add a color bar which maps values to colors.
colorbar(surf1)
title('3D frequency profile')

show()

Вот что я получаю, не настраивая значения vmin и vmax для цветовой шкалы. Максимальный цвет (красный) не соответствует максимальным пикам, а максимальное и минимальное значения цветовой шкалы не соответствуют моим минимальным и максимальным значениям на графике (примечание: min = -24 и max = 145).

first_figure

И вот что я получаю, когда устанавливаю vmin и vmax. Весь график примерно одинакового оттенка, тогда как у меня должно быть две пики красного цвета.

second_figure

Есть идеи?

Ответы [ 2 ]

0 голосов
/ 14 мая 2019

Я наконец нашел причину своей проблемы.Проблема заключалась в шаге colormap для графика (это своего рода разрешение, если я хорошо понимаю - документация cstride и rstride ).Точнее, он использует поверхность cstride * rstride для усреднения энергии сигнала на поверхности и делает цвет карты соответствующим этому среднему значению.Мои щуки были очень худыми, поэтому они не были в хорошем оттенке.Мне пришлось указать параметры cstride и rstride с меньшим значением.Поскольку их значение по умолчанию было 10.

Так что теперь у меня есть:

figure(1, figsize=(12, 6))
X = np.arange(0, 1024)
Y = np.arange(0, 2048)
X, Y = np.meshgrid(X, Y)
Z = 20 * np.log10(abs(rp))
mappable = cm.ScalarMappable()
mappable.set_array(Z)
suptitle('3D-plot and 2D-plot of frequency profile')
ax1 = subplot(121, projection='3d')
ax1.plot_surface(X, Y, Z, cmap=mappable.cmap, norm=mappable.norm, linewidth=0,
                 antialiased=False, cstride=10, rstride=1)
ax2 = subplot(122)
ax2.imshow(Z, cmap=mappable.cmap, norm=mappable.norm,
           extent=(np.min(X), np.max(X), np.min(Y), np.max(Y)),
           interpolation=None)
colorbar(mappable)

show()

Примечание: я мог бы оставить значение по умолчанию для cstride, так как мне нужно только изменить шаг row.Но это может быть полезно для кого-то еще.

И вот результат, который я получаю, и он соответствует тому, что я хочу.enter image description here

NB2: будьте осторожны, уменьшая шаг, чем больше входные данные, тем медленнее сценарий.

0 голосов
/ 13 мая 2019

Я думаю, вы просто хотите использовать Mappable материал в Matplotlib, что-то вроде:

import matplotlib.pyplot as plt

mappable = plt.cm.ScalarMappable()
mappable.set_array(Z)

, а затем позвоните plot_surface с cmap и norm из этого сопоставляемого, например:

ax.plot_surface(X, Y, Z, cmap=mappable.cmap, norm=mappable.norm, linewidth=0, antialiased=False)

затем вы можете использовать этот сопоставимый для colorbar:

plt.colorbar(mappable)

для этого следует использовать стандартную viridis карту цветов карту цветов, но ее можно указать вручную как:

mappable = plt.cm.ScalarMappable(cmap=plt.cm.viridis)

Viridis - это хорошая "воспринимаемая равномерно" цветовая карта, посмотрите на видео выше, почему Matlab jet почти всегда является плохим выбором, и почему он даже лучше, чем более современный по умолчанию parula

это просто повторное использование данных в Z как для "вертикальной" высоты, так и для цвета, поэтому я предлагаю использовать imshow, например:

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

X, Y = np.meshgrid(
    np.linspace(-2, 2, 128),
    np.linspace(-2, 2, 128),
)
Z = np.exp(-(X ** 2 + Y ** 2)) * 3 + 5

mappable = plt.cm.ScalarMappable(cmap=plt.cm.viridis)
mappable.set_array(Z)
mappable.set_clim(5, 8) # optional

fig = plt.figure(figsize=(10,4))

ax1 = fig.add_subplot(121, projection='3d')
ax1.plot_surface(X, Y, Z, cmap=mappable.cmap, norm=mappable.norm, linewidth=0, antialiased=False)

ax2 = fig.add_subplot(122)
ax2.imshow(Z, cmap=mappable.cmap, norm=mappable.norm, extent=(
    np.min(X), np.max(X), np.min(Y), np.max(Y)), interpolation='none')

plt.colorbar(mappable)
plt.tight_layout()

дает мне:

plot_surface vs imshow

Я обнаружил, что второй не 3D-сюжет позволяет мне гораздо легче увидеть, что происходит

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