Подтвердить что ты не робот

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

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

Вот как я создаю карту до сих пор. Но я не уверен, смешивает ли он цвета.

cmap = matplotlib.colors.ListedColormap(["red","violet","blue"], name='from_list', N=None)
m = cm.ScalarMappable(norm=norm, cmap=cmap)


Таким образом я сопоставляю цвета со значениями.

colors = itertools.cycle([m.to_rgba(1.22), ..])


Затем я построю его:

for i in range(0, len(array_dg)):
  plt.plot(array_dg[i], markers.next(),alpha=alpha[i], c=colors.next())


Мои проблемы:
1. Я не могу построить цветную шкалу.
2. Я не совсем уверен, что мой масштаб создает непрерывную (плавную) цветовую шкалу.

4b9b3361

Ответ 1

Ниже приведен пример создания пользовательских цветовых кодов. Докшрин имеет важное значение для понимания смысла cdict. Как только вы получите это под своим поясом, вы можете использовать cdict следующим образом:

cdict = {'red':   ((0.0, 1.0, 1.0), 
                   (0.1, 1.0, 1.0),  # red 
                   (0.4, 1.0, 1.0),  # violet
                   (1.0, 0.0, 0.0)), # blue

         'green': ((0.0, 0.0, 0.0),
                   (1.0, 0.0, 0.0)),

         'blue':  ((0.0, 0.0, 0.0),
                   (0.1, 0.0, 0.0),  # red
                   (0.4, 1.0, 1.0),  # violet
                   (1.0, 1.0, 0.0))  # blue
          }

Хотя формат cdict дает вам большую гибкость, я нахожу для простых градиенты его формат довольно неинтуитивный. Вот служебная функция, которая поможет генерировать простые LinearSegmentedColormaps:

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


def make_colormap(seq):
    """Return a LinearSegmentedColormap
    seq: a sequence of floats and RGB-tuples. The floats should be increasing
    and in the interval (0,1).
    """
    seq = [(None,) * 3, 0.0] + list(seq) + [1.0, (None,) * 3]
    cdict = {'red': [], 'green': [], 'blue': []}
    for i, item in enumerate(seq):
        if isinstance(item, float):
            r1, g1, b1 = seq[i - 1]
            r2, g2, b2 = seq[i + 1]
            cdict['red'].append([item, r1, r2])
            cdict['green'].append([item, g1, g2])
            cdict['blue'].append([item, b1, b2])
    return mcolors.LinearSegmentedColormap('CustomMap', cdict)


c = mcolors.ColorConverter().to_rgb
rvb = make_colormap(
    [c('red'), c('violet'), 0.33, c('violet'), c('blue'), 0.66, c('blue')])
N = 1000
array_dg = np.random.uniform(0, 10, size=(N, 2))
colors = np.random.uniform(-2, 2, size=(N,))
plt.scatter(array_dg[:, 0], array_dg[:, 1], c=colors, cmap=rvb)
plt.colorbar()
plt.show()

enter image description here


Кстати, for-loop

for i in range(0, len(array_dg)):
  plt.plot(array_dg[i], markers.next(),alpha=alpha[i], c=colors.next())

отображает одну точку для каждого вызова plt.plot. Это будет работать для небольшого количества очков, но во многих случаях будет очень медленным. plt.plot может рисовать только один цвет, но plt.scatter может назначать различный цвет каждой точке. Таким образом, plt.scatter - это путь.

Ответ 2

Поскольку методы, используемые в других ответах, кажутся довольно сложными для такой простой задачи, вот новый ответ:

Вместо ListedColormap, который создает дискретную LinearSegmentedColormap, вы можете использовать LinearSegmentedColormap. Это можно легко создать из списка, используя метод from_list.

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

x,y,c = zip(*np.random.rand(30,3)*4-2)

norm=plt.Normalize(-2,2)
cmap = matplotlib.colors.LinearSegmentedColormap.from_list("", ["red","violet","blue"])

plt.scatter(x,y,c=c, cmap=cmap, norm=norm)
plt.colorbar()
plt.show()

enter image description here


В более общем случае, если у вас есть список значений (например, [-2., -1, 2]) и соответствующих цветов (например, ["red","violet","blue"]), такой, что n Это значение должно соответствовать n му цвету, вы можете нормализовать значения и предоставить их в виде кортежей для метода from_list.

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

x,y,c = zip(*np.random.rand(30,3)*4-2)

cvals  = [-2., -1, 2]
colors = ["red","violet","blue"]

norm=plt.Normalize(min(cvals),max(cvals))
tuples = list(zip(map(norm,cvals), colors))
cmap = matplotlib.colors.LinearSegmentedColormap.from_list("", tuples)

plt.scatter(x,y,c=c, cmap=cmap, norm=norm)
plt.colorbar()
plt.show()

enter image description here

Ответ 3

Если вы хотите автоматизировать создание настраиваемой расходящейся цветовой карты, обычно используемой для поверхностных графиков, этот модуль в сочетании с методом @unutbu хорошо работал для я.

def diverge_map(high=(0.565, 0.392, 0.173), low=(0.094, 0.310, 0.635)):
    '''
    low and high are colors that will be used for the two
    ends of the spectrum. they can be either color strings
    or rgb color tuples
    '''
    c = mcolors.ColorConverter().to_rgb
    if isinstance(low, basestring): low = c(low)
    if isinstance(high, basestring): high = c(high)
    return make_colormap([low, c('white'), 0.5, c('white'), high])

Высокие и низкие значения могут быть либо строковыми именами цветов, либо кортежами rgb. Это результат использования демографической диаграммы: enter image description here