контур pyplot с пользовательской цветовой картой повторяет цвет вместо изменения - PullRequest
0 голосов
/ 25 сентября 2018

Я хочу нанести на график некоторые данные с помощью логарифмического цветового кода, в котором десятилетний предел обозначен бело-черным интерфейсом.Уровни серого используются, чтобы показать некоторые подразделения десятилетия.Моя проблема в том, что в каждом десятилетии есть две белые соседние области, хотя цветная карта содержит правильное количество записей (по крайней мере, я так думаю).Может кто-нибудь помочь, пожалуйста?

Тем временем я провел несколько тестов и обнаружил, что это второй цвет повторяющегося рисунка, который не используется (серый (0,25)), но я до сих пор не знаю, почему.

Вот краткая версия кода:

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

# generate data
x = y = np.linspace(-3, 3, 200)
im = 1800*np.exp(-(np.outer(x,x) + y**2))
im = im / im.max() # normalize

# set logarithic levels (with small steps)
levS = np.array([1e-3,2e-3,4e-3,6e-3,8e-3,
                 1e-2,2e-2,4e-2,6e-2,8e-2,
                 0.1,0.2,0.4,0.6,0.8,
                 1])
# (5 intervals in one decade )

# avoid white patches by filling up to lowest level
im[ im < levS.min() ] = levS.min()

# make a list of 5 colors to create a colormap from
mapColS = [plt.cm.gray(0),plt.cm.gray(0.25),plt.cm.gray(0.50), 
           plt.cm.gray(0.7),plt.cm.gray(0.99)]
# repeat 3 times for the three decades
mapColS = mapColS + mapColS + mapColS
MyCmap=colors.ListedColormap(mapColS) # make color map

fig13g = plt.figure(1000) #create figure
ax13g = fig13g.add_subplot(111)

# plot lines
cax = plt.contour(im, levS, linewidths = 0.5,
                   norm=colors.LogNorm(), colors = 'k')
# fill with colors
cax = plt.contourf(im, levS, norm=colors.LogNorm(),
                   cmap=MyCmap)  # plt.cm.jet  OR  MyCmap

# show log color bar
cbar = fig13g.colorbar(cax, orientation='vertical',
                       spacing='regular',ticks= levS)

Вот результаты:

The plot with the problem

Для сравнения, при использовании 'jet' проблем нет:
using 'jet' there is no problem

Ответы [ 2 ]

0 голосов
/ 26 сентября 2018

Проблема в том, что разные значения в итоге дают один и тот же цвет.Это связано с используемой нелинейной нормой.
Для линейной нормы цвета для слоев контурного графика будут взяты в среднем арифметическом между уровнями.Хотя это может также вызвать проблемы при сравнении изображений и контурных графиков (как показано в Как pyplot.contourf выбирает цвета из цветовой карты? ), он все равно будет использовать N уникальных цветов, используемых для уровней N + 1.

Для LogNorm вместо среднего арифметического используется среднее геометрическое .

Ниже показаны значения, используемые для получения цветов из цветовой карты.Как можно видеть, несколько оказываются в одном и том же контейнере.

enter image description here

Увеличение количества цветов позволит каждому значению быть в своей собственной цветовой корзине.

enter image description here

В принципе, именно поэтому использование цветовой карты 'jet' работает нормально, потому что у вас есть 256 разных цветов.

Следовательно, возможное решение состоит в том, чтобы использовать больше цветов для создания цветовой карты:

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

# generate data
x = y = np.linspace(-3, 3, 200)
im = 1800*np.exp(-(np.outer(x,x) + y**2))
im = im / im.max() # normalize

# set logarithic levels (with small steps)
levS = np.array([1e-3,2e-3,4e-3,6e-3,8e-3,
                 1e-2,2e-2,4e-2,6e-2,8e-2,
                 0.1,0.2,0.4,0.6,0.8,
                 1])
# (5 intervals in one decade )

# avoid white patches by filling up to lowest level
im[ im < levS.min() ] = levS.min()

# make a list of N colors to create a colormap from
N = 20
mapColS = list(plt.cm.gray(np.linspace(0,1,N)))
# repeat 3 times for the three decades
mapColR = mapColS + mapColS + mapColS
MyCmap=colors.ListedColormap(mapColR) # make color map

fig13g = plt.figure(1000) #create figure
ax13g = fig13g.add_subplot(111)

# plot lines
c = plt.contour(im, levS, linewidths = 0.5,
                   norm=colors.LogNorm(), colors = 'k')
# fill with colors
cf = plt.contourf(im, levS, norm=colors.LogNorm(),
                   cmap=MyCmap)  # plt.cm.jet  OR  MyCmap

cbar = fig13g.colorbar(cf, orientation='vertical',
                       spacing='regular',ticks= levS)                 
plt.show()

enter image description here

Недостатком этого является то, что вы теряете динамический диапазон, потому чтосамый низкий цвет не черный, а темно-серый.

Следовательно, другой вариант - рассчитать эти значения слоя и создать цветовую карту с соответствующими цветами именно в этих местах.

enter image description here

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

# generate data
x = y = np.linspace(-3, 3, 200)
im = 1800*np.exp(-(np.outer(x,x) + y**2))
im = im / im.max() # normalize

# set logarithic levels (with small steps)
levS = np.array([1e-3,2e-3,4e-3,6e-3,8e-3,
                 1e-2,2e-2,4e-2,6e-2,8e-2,
                 0.1,0.2,0.4,0.6,0.8,
                 1])
# (5 intervals in one decade )

# avoid white patches by filling up to lowest level
im[ im < levS.min() ] = levS.min()

# make a list of N colors to create a colormap from
N = 5
mapColS = list(plt.cm.gray(np.linspace(0,1,N)))
# repeat 3 times for the three decades
mapColR = mapColS + mapColS + mapColS

#calculate layer values for lognorm
layers = np.sqrt(levS[:-1]) * np.sqrt(levS[1:])
norm = colors.LogNorm(levS.min(), levS.max())
#add outmost values and colors
lvals = np.concatenate(([0.], norm(layers), [1.]))
cvals = [mapColR[0]] + mapColR + [mapColR[-1]]

# make the colormap from values and colors
MyCmap=colors.LinearSegmentedColormap.from_list("", list(zip(lvals,cvals)))

fig13g = plt.figure(1000) #create figure
ax13g = fig13g.add_subplot(111)

# plot lines
c = plt.contour(im, levS, linewidths = 0.5,
                   norm=norm, colors = 'k')
# fill with colors
cf = plt.contourf(im, levS, norm=norm,
                   cmap=MyCmap)

cbar = fig13g.colorbar(cf, orientation='vertical',
                       spacing='regular',ticks= levS)                 
plt.show()

enter image description here

0 голосов
/ 25 сентября 2018

Проблема в том, что вы повторяли одни и те же цветовые уровни mapColS 3 раза, используя mapColS = mapColS + mapColS + mapColS.Прямое решение состоит в том, чтобы создать одну непрерывную шкалу серого путем линейного деления шкалы между plt.cm.gray(0) и plt.cm.gray(0.99) на 15 равных уровней как

mapColS = [plt.cm.gray(i) for i in np.linspace(0, 0.99, 15)]

MyCmap=colors.ListedColormap(mapColS) # make color map

Выход

enter image description here

...