Как сгенерировать случайные цвета в matplotlib?


87

Какой тривиальный пример того, как генерировать случайные цвета для перехода к функциям построения графиков?

Я вызываю разброс внутри цикла и хочу, чтобы каждый график был разного цвета.

for X,Y in data:
   scatter(X, Y, c=??)

c: цвет. c может быть строкой формата одного цвета, или последовательностью цветовых спецификаций длины N, или последовательностью из N чисел, которые должны быть отображены в цвета с использованием cmap и нормы, указанных через kwargs (см. ниже). Обратите внимание, что c не должна быть одной числовой последовательностью RGB или RGBA, потому что она неотличима от массива значений, которые нужно сопоставить по цвету. Однако c может быть двумерным массивом, в котором строки имеют формат RGB или RGBA.


1
Случайно выбранный из чего? Если вы выберете случайным образом из всех доступных цветов, вы можете получить странную смесь очень разных цветов, а некоторые настолько похожи, что их будет трудно различить.
BrenBarn 06

Ответы:


141

Я вызываю разброс внутри цикла и хочу, чтобы каждый график был разным цветом.

На основании этого и вашего ответа: мне кажется, что вам действительно нужны n разные цвета для ваших наборов данных; вы хотите сопоставить целочисленные индексы 0, 1, ..., n-1с различными цветами RGB. Что-то вроде:

отображение индекса в цвет

Вот как это сделать:

import matplotlib.pyplot as plt

def get_cmap(n, name='hsv'):
    '''Returns a function that maps each index in 0, 1, ..., n-1 to a distinct 
    RGB color; the keyword argument name must be a standard mpl colormap name.'''
    return plt.cm.get_cmap(name, n)

Использование в вашем фрагменте псевдокода в вопросе:

cmap = get_cmap(len(data))
for i, (X, Y) in enumerate(data):
   scatter(X, Y, c=cmap(i))

Я создал цифру в своем ответе с помощью следующего кода:

import matplotlib.pyplot as plt

def get_cmap(n, name='hsv'):
    '''Returns a function that maps each index in 0, 1, ..., n-1 to a distinct 
    RGB color; the keyword argument name must be a standard mpl colormap name.'''
    return plt.cm.get_cmap(name, n)

def main():
    N = 30
    fig=plt.figure()
    ax=fig.add_subplot(111)   
    plt.axis('scaled')
    ax.set_xlim([ 0, N])
    ax.set_ylim([-0.5, 0.5])
    cmap = get_cmap(N)
    for i in range(N):
        rect = plt.Rectangle((i, -0.5), 1, 1, facecolor=cmap(i))
        ax.add_artist(rect)
    ax.set_yticks([])
    plt.show()

if __name__=='__main__':
    main()

Протестировано как с Python 2.7, так и с matplotlib 1.5, а также с Python 3.5 и matplotlib 2.0. Работает как положено.


1
@ user1941407 Спасибо! :) Хотел бы я знать, почему кто-то анонимно отклонил ответ.
Али

7
может это сложно
Ингрид

1
не работает? похоже, вообще не подключается к консоли python.
mjwrazor

@mjwrazor Извините, я не понимаю. Не могли бы вы пояснить, что «не работает»?
Али

Я попытался разместить метод в консоли python, консоль никогда не считывает его. Кроме того, логика в конце вашего метода не имеет смысла. Зачем возвращать метод, который вызывает другой метод, который возвращает метод выполнения. Почему бы просто не вернуть выполненный метод?
mjwrazor

76
for X,Y in data:
   scatter(X, Y, c=numpy.random.rand(3,))

1
Что, если нужно построить три значения?
panda-34

1
3 обозначают 3 значения компонентов R, G и B?
Kshitij Bajracharya

без numpy вы можете использоватьcolor=(random.uniform(0, 1), random.uniform(0, 1), random.uniform(0, 1))
azzamsa

2
Более эффективно и меньше печатать:scatter(X,Y, c=numpy.random.rand(len(X),3)
Qualia,

31

разработка ответа @ john-mee, если у вас есть произвольно длинные данные, но не нужны строго уникальные цвета:

для Python 2:

from itertools import cycle
cycol = cycle('bgrcmk')

for X,Y in data:
    scatter(X, Y, c=cycol.next())

для Python 3:

from itertools import cycle
cycol = cycle('bgrcmk')

for X,Y in data:
    scatter(X, Y, c=next(cycol))

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


27

Некоторое время меня действительно раздражал тот факт, что matplotlib не генерирует палитру со случайными цветами, поскольку это обычная потребность в задачах сегментации и кластеризации.

Просто генерируя случайные цвета, мы можем получить слишком яркие или слишком темные цвета, затрудняющие визуализацию. Кроме того, обычно нам нужно, чтобы первый или последний цвет был черным, представляя фон или выбросы. Итак, я написал небольшую функцию для повседневной работы

Вот его поведение:

new_cmap = rand_cmap(100, type='bright', first_color_black=True, last_color_black=False, verbose=True)

Сгенерированная палитра

Тогда вы просто используете new_cmap в качестве цветовой карты на matplotlib:

ax.scatter(X,Y, c=label, cmap=new_cmap, vmin=0, vmax=num_labels)

Код здесь:

def rand_cmap(nlabels, type='bright', first_color_black=True, last_color_black=False, verbose=True):
    """
    Creates a random colormap to be used together with matplotlib. Useful for segmentation tasks
    :param nlabels: Number of labels (size of colormap)
    :param type: 'bright' for strong colors, 'soft' for pastel colors
    :param first_color_black: Option to use first color as black, True or False
    :param last_color_black: Option to use last color as black, True or False
    :param verbose: Prints the number of labels and shows the colormap. True or False
    :return: colormap for matplotlib
    """
    from matplotlib.colors import LinearSegmentedColormap
    import colorsys
    import numpy as np


    if type not in ('bright', 'soft'):
        print ('Please choose "bright" or "soft" for type')
        return

    if verbose:
        print('Number of labels: ' + str(nlabels))

    # Generate color map for bright colors, based on hsv
    if type == 'bright':
        randHSVcolors = [(np.random.uniform(low=0.0, high=1),
                          np.random.uniform(low=0.2, high=1),
                          np.random.uniform(low=0.9, high=1)) for i in xrange(nlabels)]

        # Convert HSV list to RGB
        randRGBcolors = []
        for HSVcolor in randHSVcolors:
            randRGBcolors.append(colorsys.hsv_to_rgb(HSVcolor[0], HSVcolor[1], HSVcolor[2]))

        if first_color_black:
            randRGBcolors[0] = [0, 0, 0]

        if last_color_black:
            randRGBcolors[-1] = [0, 0, 0]

        random_colormap = LinearSegmentedColormap.from_list('new_map', randRGBcolors, N=nlabels)

    # Generate soft pastel colors, by limiting the RGB spectrum
    if type == 'soft':
        low = 0.6
        high = 0.95
        randRGBcolors = [(np.random.uniform(low=low, high=high),
                          np.random.uniform(low=low, high=high),
                          np.random.uniform(low=low, high=high)) for i in xrange(nlabels)]

        if first_color_black:
            randRGBcolors[0] = [0, 0, 0]

        if last_color_black:
            randRGBcolors[-1] = [0, 0, 0]
        random_colormap = LinearSegmentedColormap.from_list('new_map', randRGBcolors, N=nlabels)

    # Display colorbar
    if verbose:
        from matplotlib import colors, colorbar
        from matplotlib import pyplot as plt
        fig, ax = plt.subplots(1, 1, figsize=(15, 0.5))

        bounds = np.linspace(0, nlabels, nlabels + 1)
        norm = colors.BoundaryNorm(bounds, nlabels)

        cb = colorbar.ColorbarBase(ax, cmap=random_colormap, norm=norm, spacing='proportional', ticks=None,
                                   boundaries=bounds, format='%1i', orientation=u'horizontal')

    return random_colormap

Это также на github: https://github.com/delestro/rand_cmap


2
Благодарю. Это было очень полезно.
Эш

15

Когда меньше 9 наборов данных:

colors = "bgrcmykw"
color_index = 0

for X,Y in data:
    scatter(X,Y, c=colors[color_index])
    color_index += 1

12

Поскольку вопрос в том, How to generate random colors in matplotlib?и поскольку я искал ответ относительно pie plots, я думаю, что стоит поставить ответ здесь (для pies)

import numpy as np
from random import sample
import matplotlib.pyplot as plt
import matplotlib.colors as pltc
all_colors = [k for k,v in pltc.cnames.items()]

fracs = np.array([600, 179, 154, 139, 126, 1185])
labels = ["label1", "label2", "label3", "label4", "label5", "label6"]
explode = ((fracs == max(fracs)).astype(int) / 20).tolist()

for val in range(2):
    colors = sample(all_colors, len(fracs))
    plt.figure(figsize=(8,8))
    plt.pie(fracs, labels=labels, autopct='%1.1f%%', 
            shadow=True, explode=explode, colors=colors)
    plt.legend(labels, loc=(1.05, 0.7), shadow=True)
    plt.show()

Вывод

введите описание изображения здесь

введите описание изображения здесь


1
Эй, это именно то, что я ищу. Однако на вашем втором фото (это случается и со мной) вы получаете почти такие же цвета (бежевый / белый). Можно ли использовать этот подход, но сэмплировать таким образом, чтобы выделить более четкие цвета?
armara

9

Вот более краткая версия ответа Али, дающая один отличный цвет для каждого участка:

import matplotlib.pyplot as plt

N = len(data)
cmap = plt.cm.get_cmap("hsv", N+1)
for i in range(N):
    X,Y = data[i]
    plt.scatter(X, Y, c=cmap(i))

4

На основе ответа Али и Чампитоада:

Если вы хотите попробовать разные палитры для одного и того же, вы можете сделать это в несколько строк:

cmap=plt.cm.get_cmap(plt.cm.viridis,143)

^ 143 - количество цветов, которые вы выбираете

Я выбрал 143, потому что здесь задействован весь диапазон цветов на палитре. Что вы можете сделать, так это пробовать n-й цвет на каждой итерации, чтобы получить эффект цветовой карты.

n=20 for i,(x,y) in enumerate(points): plt.scatter(x,y,c=cmap(n*i))



1
enter code here

import numpy as np

clrs = np.linspace( 0, 1, 18 )  # It will generate 
# color only for 18 for more change the number
np.random.shuffle(clrs)
colors = []
for i in range(0, 72, 4):
    idx = np.arange( 0, 18, 1 )
    np.random.shuffle(idx)
    r = clrs[idx[0]]
    g = clrs[idx[1]]
    b = clrs[idx[2]]
    a = clrs[idx[3]]
    colors.append([r, g, b, a])

Назначьте этот список цветов цвету при рисовании графика
Сантош Магадум

1

Если вы хотите, чтобы цвета были различимы, но не знаете, сколько цветов нужно. Попробуйте что-нибудь подобное. Он выбирает цвета с противоположных сторон спектра и систематически увеличивает детализацию.

import math

def calc(val, max = 16):
    if val < 1:
        return 0
    if val == 1:
        return max

    l = math.floor(math.log2(val-1))    #level 
    d = max/2**(l+1)                    #devision
    n = val-2**l                        #node
    return d*(2*n-1)
import matplotlib.pyplot as plt

N = 16
cmap = cmap = plt.cm.get_cmap('gist_rainbow', N)

fig, axs = plt.subplots(2)
for ax in axs:
    ax.set_xlim([ 0, N])
    ax.set_ylim([-0.5, 0.5])
    ax.set_yticks([])

for i in range(0,N+1):
    v = int(calc(i, max = N))
    rect0 = plt.Rectangle((i, -0.5), 1, 1, facecolor=cmap(i))
    rect1 = plt.Rectangle((i, -0.5), 1, 1, facecolor=cmap(v))
    axs[0].add_artist(rect0)
    axs[1].add_artist(rect1)

plt.xticks(range(0, N), [int(calc(i, N)) for i in range(0, N)])
plt.show()

вывод

Спасибо @Ali за предоставление базовой реализации.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.