Як генерувати випадкові кольори в matplotlib?


83

Який тривіальний приклад того, як генерувати випадкові кольори для переходу до графічних функцій?

Я називаю розкидання всередині циклу і хочу, щоб кожна ділянка мала інший колір.

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

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


1
Вибраний навмання з чого? Якщо ви вибрали випадковим чином серед усіх доступних кольорів, ви можете отримати дивну суміш дуже різних кольорів, а деякі настільки подібні, що їх важко розрізнити.
BrenBarn

Відповіді:


139

Я закликаю розкидання всередині циклу і хочу, щоб кожна ділянка була іншого кольору.

Виходячи з цього та вашої відповіді: Мені здається, ви насправді хочете 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

1
Ефективніше та менше друку: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
Дякую. Це було дуже корисно.
Еш

14

Коли менше 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
Гей, це саме те, що я шукаю. Однак на вашому другому знімку (це трапляється і зі мною) ви отримуєте майже однакові кольори (бежевий / білий). Чи можна використовувати цей підхід, але взяти зразок таким чином, щоб виділити більш чіткі кольори?
Армара

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])

Призначте цей список кольорів кольором на час малювання графіка
Santosh Magadum

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.