Встановлення різного кольору для кожної серії в розкиданому сюжеті на matplotlib


162

Припустимо, у мене є три набори даних:

X = [1,2,3,4]
Y1 = [4,8,12,16]
Y2 = [1,4,9,16]

Я можу розсіяти сюжет так:

from matplotlib import pyplot as plt
plt.scatter(X,Y1,color='red')
plt.scatter(X,Y2,color='blue')
plt.show()

Як я можу це зробити за допомогою 10 наборів?

Я шукав це і міг знайти будь-яку посилання на те, що я прошу.

Редагувати: уточнюючи (сподіваюся) моє запитання

Якщо я називаю розкидання кілька разів, я можу встановити один і той же колір на кожному розкиданні. Також я знаю, що можна встановити кольоровий масив вручну, але впевнений, що є кращий спосіб це зробити. Після цього у мене виникає запитання: "Як я можу автоматично розсипати графіки моїх декількох наборів даних, кожен з яких має інший колір.

Якщо це допоможе, я можу легко призначити унікальний номер кожному набору даних.


1
Що тут питання? Колір також може бути масивом, але що ви не можете вирішити, просто зателефонувавши в розсіювання кілька разів?
seberg

1
Якщо я називаю розкидання кілька разів, я отримую однакові кольори. Я оновлю своє запитання.
Йотам

Відповіді:


269

Я не знаю, що ви маєте на увазі під «вручну». Ви можете вибрати кольорову карту і зробити кольоровий масив досить легко:

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

x = np.arange(10)
ys = [i+x+(i*x)**2 for i in range(10)]

colors = cm.rainbow(np.linspace(0, 1, len(ys)))
for y, c in zip(ys, colors):
    plt.scatter(x, y, color=c)

Графік Matplotlib з різними кольорами

Або ви можете зробити свій власний кольоровий циклер, використовуючи itertools.cycleта вказавши кольори, які ви хочете перекинути, використовуючи, nextщоб отримати потрібний. Наприклад, з 3 кольорами:

import itertools

colors = itertools.cycle(["r", "b", "g"])
for y in ys:
    plt.scatter(x, y, color=next(colors))

Графік Matplotlib лише з 3 кольорами

Подумайте про це, можливо, чистіше не використовувати zipз першим ні:

colors = iter(cm.rainbow(np.linspace(0, 1, len(ys))))
for y in ys:
    plt.scatter(x, y, color=next(colors))

1
+1. Цикл itertools, мабуть, не є хорошою ідеєю в цій ситуації, оскільки в кінцевому підсумку це буде безліч наборів даних, що мають один і той же колір.
Девід Робінсон

1
@DavidRobinson: не, якщо ви вкажете всі десять, хоча я погоджуюсь, що велосипедний тип перемагає мету там ..: ^)
DSM

Точно- тоді це не цикл :)
Девід Робінсон

4
@macrocosme: працює для мене. Додавши plt.legend(['c{}'.format(i) for i in range(len(ys))], loc=2, bbox_to_anchor=(1.05, 1), borderaxespad=0., fontsize=11)до нижньої частини вище сказане дає мені легенду з кольорами.
DSM

рішення itertools чудово, коли ви хочете уникати деяких кольорів. У моєму випадку, оскільки фон чорний, я хочу уникати чорного.
Фабріціо

50

Нормальний спосіб побудови ділянок з точками різних кольорів у matplotlib - це передавання списку кольорів як параметр.

Наприклад:

import matplotlib.pyplot
matplotlib.pyplot.scatter([1,2,3],[4,5,6],color=['red','green','blue'])

3 кольори

Коли у вас є список списків, і ви хочете, щоб вони були кольоровими за списком. Я думаю, що найелегантніший спосіб - це те, що запропоновано @DSM, просто зробіть цикл, який робить кілька дзвінків для розсіювання.

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

import matplotlib
import numpy as np

X = [1,2,3,4]
Ys = np.array([[4,8,12,16],
      [1,4,9,16],
      [17, 10, 13, 18],
      [9, 10, 18, 11],
      [4, 15, 17, 6],
      [7, 10, 8, 7],
      [9, 0, 10, 11],
      [14, 1, 15, 5],
      [8, 15, 9, 14],
       [20, 7, 1, 5]])
nCols = len(X)  
nRows = Ys.shape[0]

colors = matplotlib.cm.rainbow(np.linspace(0, 1, len(Ys)))

cs = [colors[i//len(X)] for i in range(len(Ys)*len(X))] #could be done with numpy's repmat
Xs=X*nRows #use list multiplication for repetition
matplotlib.pyplot.scatter(Xs,Ys.flatten(),color=cs)

Все накреслено

cs = [array([ 0.5,  0. ,  1. ,  1. ]),
 array([ 0.5,  0. ,  1. ,  1. ]),
 array([ 0.5,  0. ,  1. ,  1. ]),
 array([ 0.5,  0. ,  1. ,  1. ]),
 array([ 0.28039216,  0.33815827,  0.98516223,  1.        ]),
 array([ 0.28039216,  0.33815827,  0.98516223,  1.        ]),
 array([ 0.28039216,  0.33815827,  0.98516223,  1.        ]),
 array([ 0.28039216,  0.33815827,  0.98516223,  1.        ]),
 ...
 array([  1.00000000e+00,   1.22464680e-16,   6.12323400e-17,
          1.00000000e+00]),
 array([  1.00000000e+00,   1.22464680e-16,   6.12323400e-17,
          1.00000000e+00]),
 array([  1.00000000e+00,   1.22464680e-16,   6.12323400e-17,
          1.00000000e+00]),
 array([  1.00000000e+00,   1.22464680e-16,   6.12323400e-17,
          1.00000000e+00])]

19

Просте виправлення

Якщо у вас є лише один тип колекцій (наприклад, розкидання без смужок помилок), ви також можете змінити кольори після того, як ви їх побудували, це іноді простіше виконати.

import matplotlib.pyplot as plt
from random import randint
import numpy as np

#Let's generate some random X, Y data X = [ [frst group],[second group] ...]
X = [ [randint(0,50) for i in range(0,5)] for i in range(0,24)]
Y = [ [randint(0,50) for i in range(0,5)] for i in range(0,24)]
labels = range(1,len(X)+1)

fig = plt.figure()
ax = fig.add_subplot(111)
for x,y,lab in zip(X,Y,labels):
        ax.scatter(x,y,label=lab)

Єдиний фрагмент коду, який вам потрібен:

#Now this is actually the code that you need, an easy fix your colors just cut and paste not you need ax.
colormap = plt.cm.gist_ncar #nipy_spectral, Set1,Paired  
colorst = [colormap(i) for i in np.linspace(0, 0.9,len(ax.collections))]       
for t,j1 in enumerate(ax.collections):
    j1.set_color(colorst[t])


ax.legend(fontsize='small')

Вихід дає різні кольори, навіть якщо у вас є багато різних ділянок розкидання в одному субплоті.

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


це чудово, але як би ви, наприклад, додали панелі помилок одного кольору за допомогою цієї функції? @GM
PEBKAC

1
Привіт @PEBKAC, дякую, що вказав на це, я сьогодні дуже наполегливо намагався, щоб він працював і в цьому випадку, але я не зміг знайти рішення, тому я відредагував це питання та попередив інших користувачів. Дякую!
GM

Привіт @GM, вибачте, що я опублікував декілька коментарів, перш ніж допрацювати рішення, яке описано тут:
stackoverflow.com/q/51444364/7541421

1
Я використовував інший метод, щоб призначити кольори для кожної серії в графіку розкидання. Зараз це працює, на жаль, я не зміг приступити до вашого елегантного рішення, коли справа дойшла до панелей помилок, я все ще дуже вдячний за ваш надзвичайно корисний пост! Ура!
PEBKAC

7

Ви завжди можете використовувати plot()функцію так:

import matplotlib.pyplot as plt

import numpy as np

x = np.arange(10)
ys = [i+x+(i*x)**2 for i in range(10)]
plt.figure()
for y in ys:
    plt.plot(x, y, 'o')
plt.show()

сюжет як розкидання, але змінює кольори


6

Це запитання є дещо складним перед січнем 2013 та matplotlib 1.3.1 (серпня 2013), що є найстарішою стабільною версією, яку ви можете знайти на веб-сайті matpplotlib. Але після цього це досить банально.

Тому що теперішня версія matplotlib.pylab.scatterпідтримки призначає: масив рядка імені кольору, масив плаваючого числа з кольоровою картою, масив RGB або RGBA.

ця відповідь присвячена нескінченному захопленню @ Oxinabox виправити версію себе 2013 року в 2015 році.


у вас є два варіанти використання команди розсіяння з декількома кольорами в одному дзвінку.

  1. в якості pylab.scatterпідтримки команд використовуйте масив RGBA, щоб робити будь-який колір;

  2. ще на початку 2013 року це зробити не існує, оскільки команда підтримує лише один колір для всього набору точок розкидання. Коли я робив свій проект на 10000 рядків, я з'ясував загальне рішення для його обходу. так що це дуже липко, але я можу це робити в будь-якій формі, кольорі, розмірі та прозорості. ця хитрість також може бути застосована для малювання колекції контурів, колекції ліній….

код також натхненний вихідним кодом pyplot.scatter, я просто дублював те, що розкидає, не запускаючи його для малювання.

команда pyplot.scatterповертає PatchCollectionObject, у файлі "matplotlib / collections.py" приватну змінну _facecolorsвCollection класі та метод set_facecolors.

тому, коли у вас є точки розкидання, ви можете зробити це:

# rgbaArr is a N*4 array of float numbers you know what I mean
# X is a N*2 array of coordinates
# axx is the axes object that current draw, you get it from
# axx = fig.gca()

# also import these, to recreate the within env of scatter command 
import matplotlib.markers as mmarkers
import matplotlib.transforms as mtransforms
from matplotlib.collections import PatchCollection
import matplotlib.markers as mmarkers
import matplotlib.patches as mpatches


# define this function
# m is a string of scatter marker, it could be 'o', 's' etc..
# s is the size of the point, use 1.0
# dpi, get it from axx.figure.dpi
def addPatch_point(m, s, dpi):
    marker_obj = mmarkers.MarkerStyle(m)
    path = marker_obj.get_path()
    trans = mtransforms.Affine2D().scale(np.sqrt(s*5)*dpi/72.0)
    ptch = mpatches.PathPatch(path, fill = True, transform = trans)
    return ptch

patches = []
# markerArr is an array of maker string, ['o', 's'. 'o'...]
# sizeArr is an array of size float, [1.0, 1.0. 0.5...]

for m, s in zip(markerArr, sizeArr):
    patches.append(addPatch_point(m, s, axx.figure.dpi))

pclt = PatchCollection(
                patches,
                offsets = zip(X[:,0], X[:,1]),
                transOffset = axx.transData)

pclt.set_transform(mtransforms.IdentityTransform())
pclt.set_edgecolors('none') # it's up to you
pclt._facecolors = rgbaArr

# in the end, when you decide to draw
axx.add_collection(pclt)
# and call axx's parent to draw_idle()

тож читати її складно, і в 2013 році я використовував пітон протягом 1 року. то чому люди хочуть знати, як це зробити? після того, як це запрацює, я ніколи не намагаюся переглянути це знову. мій проект полягав у тому, щоб намалювати багато візуалізації, з вищевказаним кодом робочий потік був упорядкований.
Хуалін

1

Це працює для мене:

для кожної серії використовуйте випадковий генератор кольорових колекцій

c = color[np.random.random_sample(), np.random.random_sample(), np.random.random_sample()]

Я не знаю , що це ваша змінна колір, але використовуючи свій підхід, можна зробити що - щось на кшталт: plt.scatter(your values to the graph, color= (np.random.random_sample(), np.random.random_sample(), np.random.random_sample()) ). Ви згадали про генератор RGB і оголосили список RGB, генератори оголошені між '()'
Джоел Карнейро

0

Набагато швидше рішення для великих наборів даних та обмеженої кількості кольорів - це використання Pandas та функції groupby:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import time


# a generic set of data with associated colors
nsamples=1000
x=np.random.uniform(0,10,nsamples)
y=np.random.uniform(0,10,nsamples)
colors={0:'r',1:'g',2:'b',3:'k'}
c=[colors[i] for i in np.round(np.random.uniform(0,3,nsamples),0)]

plt.close('all')

# "Fast" Scatter plotting
starttime=time.time()
# 1) make a dataframe
df=pd.DataFrame()
df['x']=x
df['y']=y
df['c']=c
plt.figure()
# 2) group the dataframe by color and loop
for g,b in df.groupby(by='c'):
    plt.scatter(b['x'],b['y'],color=g)
print('Fast execution time:', time.time()-starttime)

# "Slow" Scatter plotting
starttime=time.time()
plt.figure()
# 2) group the dataframe by color and loop
for i in range(len(x)):
    plt.scatter(x[i],y[i],color=c[i])
print('Slow execution time:', time.time()-starttime)

plt.show()
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.