Làm thế nào để tạo màu ngẫu nhiên trong matplotlib?


83

Ví dụ đơn giản về cách tạo màu ngẫu nhiên để chuyển đến các hàm vẽ đồ thị là gì?

Tôi đang gọi phân tán bên trong một vòng lặp và muốn mỗi âm mưu có một màu khác nhau.

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

c: một màu. c có thể là một chuỗi định dạng màu duy nhất, hoặc một chuỗi các thông số kỹ thuật màu có độ dài N, hoặc một chuỗi N số được ánh xạ với các màu bằng cách sử dụng cmap và định mức được chỉ định thông qua kwargs (xem bên dưới). Lưu ý rằng c không được là một chuỗi RGB hoặc RGBA số đơn lẻ vì không thể phân biệt được với một mảng giá trị được ánh xạ màu. Tuy nhiên, c có thể là mảng 2-D trong đó các hàng là RGB hoặc RGBA.


1
Chọn ngẫu nhiên từ cái gì? Nếu bạn chọn ngẫu nhiên từ tất cả các màu có sẵn, bạn có thể nhận được sự pha trộn kỳ lạ của một số màu rất khác nhau và một số giống nhau đến mức khó phân biệt.
BrenBarn

Câu trả lời:


139

Tôi đang gọi phân tán bên trong một vòng lặp và muốn mỗi âm mưu có một màu khác nhau.

Dựa trên điều đó, và câu trả lời của bạn: Đối với tôi, có vẻ như bạn thực sự muốn có màu sắc n riêng biệt cho bộ dữ liệu của mình; bạn muốn ánh xạ các chỉ số số nguyên thành các 0, 1, ..., n-1màu RGB riêng biệt. Cái gì đó như:

ánh xạ chỉ mục sang màu

Đây là chức năng để làm điều đó:

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)

Cách sử dụng trong đoạn mã giả của bạn trong câu hỏi:

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

Tôi đã tạo hình trong câu trả lời của mình với mã sau:

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

Đã thử nghiệm với cả Python 2.7 & matplotlib 1.5 và với Python 3.5 & matplotlib 2.0. Nó hoạt động như mong đợi.


1
@ user1941407 Cảm ơn! :) Tôi ước tôi biết tại sao ai đó ẩn danh từ chối câu trả lời.
Ali

7
có lẽ nó phức tạp
Ingrid

1
dường như không hoạt động? dường như không cắm vào bảng điều khiển python.
mjwrazor

@mjwrazor Xin lỗi, tôi không theo dõi. Bạn có thể giải thích những gì "không hoạt động"?
Ali

Tôi đã cố gắng đặt phương thức trong bảng điều khiển python, bảng điều khiển không bao giờ đọc nó trong. Ngoài ra, logic ở cuối phương thức của bạn không có ý nghĩa. Tại sao trả về một phương thức gọi một phương thức khác trả về một phương thức thực thi. Tại sao không chỉ trả về phương thức đã thực thi?
mjwrazor

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

1
Điều gì sẽ xảy ra nếu có ba giá trị để vẽ biểu đồ?
panda-34,

1
3 có phải là viết tắt của 3 giá trị thành phần R, G và B không?
Kshitij Bajracharya

mà không NumPy, bạn có thể sử dụngcolor=(random.uniform(0, 1), random.uniform(0, 1), random.uniform(0, 1))
azzamsa

1
Hiệu quả hơn và gõ ít hơn:scatter(X,Y, c=numpy.random.rand(len(X),3)
Qualia

31

xây dựng câu trả lời của @ john-mee, nếu bạn có dữ liệu dài tùy ý nhưng không cần màu sắc riêng biệt:

cho python 2:

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

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

cho python 3:

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

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

điều này có lợi thế là màu sắc dễ kiểm soát và nó ngắn.


27

Trong một thời gian, tôi thực sự khó chịu vì matplotlib không tạo ra các bản đồ màu với màu sắc ngẫu nhiên, vì đây là nhu cầu phổ biến cho các tác vụ phân đoạn và phân cụm.

Bằng cách chỉ tạo ra các màu ngẫu nhiên, chúng ta có thể kết thúc bằng một số màu quá sáng hoặc quá tối, gây khó khăn cho việc hình dung. Ngoài ra, thông thường chúng ta cần màu đầu tiên hoặc màu cuối cùng là màu đen, đại diện cho nền hoặc các phần ngoại lai. Vì vậy, tôi đã viết một hàm nhỏ cho công việc hàng ngày của mình

Đây là hành vi của nó:

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

Bản đồ màu đã tạo

Hơn là bạn chỉ sử dụng new_cmap làm bản đồ màu của mình trên matplotlib:

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

Mã ở đây:

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

Nó cũng có trên github: https://github.com/delestro/rand_cmap


2
Cảm ơn. Nó rất hữu ích.
Ash

14

Khi ít hơn 9 bộ dữ liệu:

colors = "bgrcmykw"
color_index = 0

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

12

Vì câu hỏi là How to generate random colors in matplotlib?và khi tôi đang tìm kiếm câu trả lời liên quan pie plots, tôi nghĩ rằng rất đáng để đặt câu trả lời ở đây (cho 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()

Đầu ra

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây


1
Này, đây chính xác là những gì tôi đang tìm kiếm. Tuy nhiên, trong bức ảnh thứ hai của bạn (điều này cũng xảy ra với tôi), bạn nhận được các màu gần như giống nhau (màu be / trắng). Có thể sử dụng phương pháp này nhưng lấy mẫu theo cách chọn ra các màu khác biệt hơn không?
armara 23/07/19

9

Đây là một phiên bản ngắn gọn hơn về câu trả lời của Ali với một màu sắc riêng biệt cho mỗi cốt truyện:

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

Dựa trên câu trả lời của Ali và Champitoad:

Nếu bạn muốn thử các bảng màu khác nhau cho giống nhau, bạn có thể thực hiện việc này trong một vài dòng:

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

^ 143 là số màu bạn đang lấy mẫu

Tôi chọn 143 vì toàn bộ dải màu trên bản đồ màu đều có tác dụng ở đây. Những gì bạn có thể làm là lấy mẫu màu thứ n mỗi lần lặp lại để có được hiệu ứng bản đồ màu.

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

Gán này danh sách màu sắc trong màu nhân khi vẽ đồ thị
Santosh Magadum

1

Nếu bạn muốn đảm bảo màu sắc khác biệt - nhưng không biết cần bao nhiêu màu. Hãy thử một cái gì đó như thế này. Nó chọn màu từ các mặt đối diện của quang phổ và tăng độ chi tiết một cách có hệ thống.

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

đầu ra

Cảm ơn @Ali đã cung cấp cách triển khai cơ sở.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.