Цветовая карта с максимально различимыми цветами

Используя matplotlib в Python, я рисую от 20 до 50 строк. Используя скользящие цветовые шкалы matplotlib, они становятся неразличимыми после нанесения определенного количества строк (задолго до 20).

Хотя я видел несколько примеров кода в Matlab и C # для создания цветовых карт произвольного количества цветов, которые максимально отличимы друг от друга, я ничего не могу найти для Python.

Может ли кто-нибудь указать мне направление чего-то в Python, что сделает это?

Ваше здоровье


person WRJ    schedule 09.03.2017    source источник
comment
Возможный дубликат создания более 20 уникальных цветов легенды с использованием matplotlib   -  person tmdavison    schedule 09.03.2017
comment
Этот ответ, по-видимому, направлен на то, чтобы избежать циклического изменения цвета в индексе. Я знаю, как использовать цветовые карты, чтобы избежать этого, но хочу алгоритмически создать набор цветов, которые можно легко различить на глаз. Как только вы получите 20 строк на графике с использованием цветовой карты hsv, вы получите 5 оттенков зеленого, которые настолько похожи, что это невозможно.   -  person WRJ    schedule 09.03.2017
comment
Этот может помочь.   -  person ImportanceOfBeingErnest    schedule 09.03.2017
comment
Это здорово, спасибо. Я просто скопирую список цветов и буду обращаться к ним по мере необходимости.   -  person WRJ    schedule 09.03.2017
comment
Этот инструмент позволит вам создать собственный список. Точно так же этот. Идея всегда одна и та же: начните со списка множества цветов и, в зависимости от необходимости, выберите из него N подмножество элементов.   -  person ImportanceOfBeingErnest    schedule 09.03.2017
comment
Спасибо, я тоже их попробую!   -  person WRJ    schedule 09.03.2017
comment
Рассматривали ли вы другой метод построения графиков для отображения вашей информации? Возможно, сюжет в 20-50 строк — не лучший способ передать ваши данные.   -  person wflynny    schedule 09.03.2017


Ответы (2)


Мне понравилась идея палитры, созданная @xuancong84, и я немного изменил его код, чтобы он не зависел от альфа-канала. Я оставлю это здесь, чтобы другие могли использовать, спасибо, @xuancong84!

import math

import numpy as np
from matplotlib.colors import ListedColormap
from matplotlib.cm import hsv


def generate_colormap(number_of_distinct_colors: int = 80):
    if number_of_distinct_colors == 0:
        number_of_distinct_colors = 80

    number_of_shades = 7
    number_of_distinct_colors_with_multiply_of_shades = int(math.ceil(number_of_distinct_colors / number_of_shades) * number_of_shades)

    # Create an array with uniformly drawn floats taken from <0, 1) partition
    linearly_distributed_nums = np.arange(number_of_distinct_colors_with_multiply_of_shades) / number_of_distinct_colors_with_multiply_of_shades

    # We are going to reorganise monotonically growing numbers in such way that there will be single array with saw-like pattern
    #     but each saw tooth is slightly higher than the one before
    # First divide linearly_distributed_nums into number_of_shades sub-arrays containing linearly distributed numbers
    arr_by_shade_rows = linearly_distributed_nums.reshape(number_of_shades, number_of_distinct_colors_with_multiply_of_shades // number_of_shades)

    # Transpose the above matrix (columns become rows) - as a result each row contains saw tooth with values slightly higher than row above
    arr_by_shade_columns = arr_by_shade_rows.T

    # Keep number of saw teeth for later
    number_of_partitions = arr_by_shade_columns.shape[0]

    # Flatten the above matrix - join each row into single array
    nums_distributed_like_rising_saw = arr_by_shade_columns.reshape(-1)

    # HSV colour map is cyclic (https://matplotlib.org/tutorials/colors/colormaps.html#cyclic), we'll use this property
    initial_cm = hsv(nums_distributed_like_rising_saw)

    lower_partitions_half = number_of_partitions // 2
    upper_partitions_half = number_of_partitions - lower_partitions_half

    # Modify lower half in such way that colours towards beginning of partition are darker
    # First colours are affected more, colours closer to the middle are affected less
    lower_half = lower_partitions_half * number_of_shades
    for i in range(3):
        initial_cm[0:lower_half, i] *= np.arange(0.2, 1, 0.8/lower_half)

    # Modify second half in such way that colours towards end of partition are less intense and brighter
    # Colours closer to the middle are affected less, colours closer to the end are affected more
    for i in range(3):
        for j in range(upper_partitions_half):
            modifier = np.ones(number_of_shades) - initial_cm[lower_half + j * number_of_shades: lower_half + (j + 1) * number_of_shades, i]
            modifier = j * modifier / upper_partitions_half
            initial_cm[lower_half + j * number_of_shades: lower_half + (j + 1) * number_of_shades, i] += modifier

    return ListedColormap(initial_cm)

Вот такие цвета у меня получились:

from matplotlib import pyplot as plt
import numpy as np

N = 16
M = 7
H = np.arange(N*M).reshape([N,M])
fig = plt.figure(figsize=(10, 10))
ax = plt.pcolor(H, cmap=generate_colormap(N*M))
plt.show()

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

person Greg0ry    schedule 31.01.2020
comment
Фантастика, как раз то, что мне нужно для диаграммы Ганта с ~ 50 задачами. Спасибо! - person Grumpybeard; 24.04.2020

Недавно тоже столкнулся с такой же проблемой. Поэтому я создал следующий простой код Python для создания визуально различимых цветов для jupyter Notebook Matplotlib. Это не совсем максимально различимо для восприятия, но работает лучше, чем большинство встроенных цветовых карт в matplotlib.

Алгоритм разбивает шкалу HSV на 2 фрагмента: 1-й фрагмент с увеличением значения RGB, 2-й фрагмент с уменьшением альфа-канала, чтобы цвет мог сливаться с белым фоном.

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

Кроме того, различимость цвета сильно зависит от экрана вашего компьютера, проектора и т. д. Цветовая палитра, различимая на одном экране, не обязательно подразумевается на другом. Вы должны физически протестировать его, если хотите использовать для презентации.

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

def generate_colormap(N):
    arr = np.arange(N)/N
    N_up = int(math.ceil(N/7)*7)
    arr.resize(N_up)
    arr = arr.reshape(7,N_up//7).T.reshape(-1)
    ret = matplotlib.cm.hsv(arr)
    n = ret[:,3].size
    a = n//2
    b = n-a
    for i in range(3):
        ret[0:n//2,i] *= np.arange(0.2,1,0.8/a)
    ret[n//2:,3] *= np.arange(1,0.1,-0.9/b)
#     print(ret)
    return ret

N = 16
H = np.arange(N*N).reshape([N,N])
fig = plt.figure(figsize=(10, 10))
ax = plt.pcolor(H, cmap=ListedColormap(generate_colormap(N*N)))

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

person xuancong84    schedule 13.09.2019