Ustawianie innego koloru dla każdej serii na wykresie punktowym w matplotlib

162

Załóżmy, że mam trzy zestawy danych:

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

Mogę rozproszyć wykres:

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

Jak mogę to zrobić z 10 zestawami?

Szukałem tego i mogłem znaleźć jakiekolwiek odniesienie do tego, o co pytam.

Edycja: wyjaśnienie (miejmy nadzieję) moje pytanie

Jeśli wywołam scatter wiele razy, mogę ustawić ten sam kolor tylko na każdym scatter. Wiem też, że mogę ręcznie ustawić tablicę kolorów, ale jestem pewien, że jest na to lepszy sposób. Moje pytanie brzmi zatem: „Jak mogę automatycznie wykreślić rozproszenie moich kilku zestawów danych, z których każdy ma inny kolor.

Jeśli to pomoże, mogę łatwo przypisać unikalny numer do każdego zestawu danych.

Yotam
źródło
1
O co tu chodzi? Kolor może być również tablicą, ale czego nie możesz rozwiązać, po prostu wywołując wielokrotnie scatter?
seberg
1
Jeśli wielokrotnie wywołam scatter, otrzymam te same kolory. Zaktualizuję moje pytanie.
Yotam

Odpowiedzi:

269

Nie wiem, co masz na myśli mówiąc „ręcznie”. Możesz wybrać mapę kolorów i łatwo stworzyć tablicę kolorów:

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)

Wykres Matplotlib z różnymi kolorami

Możesz też stworzyć swój własny cykler kolorów, używając itertools.cyclei określając kolory, które chcesz zapętlić, używając, nextaby uzyskać ten, który chcesz. Na przykład przy 3 kolorach:

import itertools

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

Wykres Matplotlib z tylko 3 kolorami

Pomyśl o tym, może lepiej jest nie używać zipz pierwszym ani:

colors = iter(cm.rainbow(np.linspace(0, 1, len(ys))))
for y in ys:
    plt.scatter(x, y, color=next(colors))
DSM
źródło
1
+1. Cykl itertools prawdopodobnie nie jest jednak dobrym pomysłem w tej sytuacji, ponieważ skończyłby się z wieloma zestawami danych o tym samym kolorze.
David Robinson
1
@DavidRobinson: nie, jeśli podasz wszystkie dziesięć, chociaż zgadzam się, że kolarstwo w pewnym sensie mija się z celem ..: ^)
DSM
Dokładnie - to nie jest cykl :)
David Robinson
4
@macrocosme: działa dla mnie. Dodając plt.legend(['c{}'.format(i) for i in range(len(ys))], loc=2, bbox_to_anchor=(1.05, 1), borderaxespad=0., fontsize=11)na dole powyższe daje mi legendę z kolorami.
DSM,
rozwiązanie itertools jest świetne, gdy chcesz uniknąć niektórych kolorów. W moim przypadku, ponieważ tło jest czarne, chcę uniknąć czerni.
Fabrizio
50

Normalnym sposobem kreślenia wykresów z punktami w różnych kolorach w matplotlib jest przekazanie listy kolorów jako parametru.

Na przykład:

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

3 kolory

Gdy masz listę list i chcesz je pokolorować na liście. Myślę, że najbardziej elegancki sposób jest sugerowany przez @DSM, po prostu wykonaj pętlę, wykonując wiele wywołań rozproszenia.

Ale jeśli z jakiegoś powodu chciałeś to zrobić za pomocą jednego połączenia, możesz sporządzić dużą listę kolorów, ze zrozumieniem listy i odrobiną podziału podłogi:

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)

Wszystko wykreślone

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])]
Lyndon White
źródło
19

Łatwa naprawa

Jeśli masz tylko jeden typ kolekcji (np. Rozproszone bez słupków błędów), możesz również zmienić kolory po ich wykreśleniu, co czasami jest łatwiejsze do wykonania.

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)

Jedyny fragment kodu, którego potrzebujesz:

#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')

Wynik daje różne kolory, nawet jeśli masz wiele różnych wykresów rozrzutu na tym samym wykresie podrzędnym.

wprowadź opis obrazu tutaj

GM
źródło
to świetnie, ale jak możesz na przykład dodać paski błędów o tym samym kolorze za pomocą tej funkcji? @GM
PEBKAC
1
Cześć @PEBKAC, dziękuję za wskazanie tego, bardzo się starałem, aby to zadziałało również w tym przypadku, ale nie mogłem znaleźć żadnego rozwiązania, więc zredagowałem pytanie i ostrzegłem innych użytkowników. Dzięki!
GM
Cześć @GM, przepraszam, opublikowałem kilka komentarzy przed sfinalizowaniem rozwiązania, które jest opisane tutaj: stackoverflow.com/q/51444364/7541421
PEBKAC
1
Użyłem innej metody, aby przypisać kolory do każdej serii na wykresie punktowym. Teraz to działa, niestety nie mogłem przejść do Twojego eleganckiego rozwiązania, jeśli chodzi o paski błędów, nadal jestem bardzo wdzięczny za super pomocny post! Twoje zdrowie!
PEBKAC,
7

Zawsze możesz użyć tej plot()funkcji w następujący sposób:

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

wykres jako punktowy, ale zmienia kolory

Ophir Carmi
źródło
6

To pytanie jest trochę podchwytliwe przed styczniem 2013 i matplotlib 1.3.1 (sierpień 2013), który jest najstarszą stabilną wersją, jaką można znaleźć na stronie matpplotlib. Ale potem jest to dość trywialne.

Ponieważ obecna wersja matplotlib.pylab.scatter obsługuje przypisywanie: tablica nazw kolorów, tablica liczb zmiennoprzecinkowych z mapą kolorów, tablica RGB lub RGBA.

ta odpowiedź jest poświęcona nieskończonej pasji @ Oxinabox do poprawiania mojej wersji z 2013 roku w 2015 roku.


masz dwie możliwości użycia polecenia rozproszenia z wieloma kolorami w jednym wywołaniu.

  1. jako pylab.scatterobsługa poleceń użyj tablicy RGBA, aby zrobić dowolny kolor;

  2. na początku 2013 roku nie było takiej możliwości, ponieważ polecenie obsługuje tylko jeden kolor dla całej kolekcji punktów rozrzutu. Kiedy wykonywałem swój projekt o długości 10000 linii, znalazłem ogólne rozwiązanie, aby go ominąć. więc jest bardzo lepki, ale mogę to zrobić w dowolnym kształcie, kolorze, rozmiarze i przezroczystości. ta sztuczka może być również zastosowana do narysowania kolekcji ścieżek, kolekcji linii ...

kod jest również inspirowany kodem źródłowym pyplot.scatter , po prostu zduplikowałem to, co robi scatter bez wyzwalania go do rysowania.

polecenie pyplot.scatterzwraca PatchCollectionobiekt, w pliku „matplotlib / collections.py” prywatną zmienną _facecolorsw Collectionklasie i metodzie set_facecolors.

więc zawsze, gdy masz do narysowania punkty rozproszone, możesz to zrobić:

# 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()
Hualin
źródło
więc czytanie jest trochę skomplikowane iw 2013 roku używałem Pythona przez 1 rok. więc dlaczego ludzie mieliby chcieć wiedzieć, jak to zrobić? po tym, jak to zadziałało, nigdy nie zawracam sobie głowy spojrzeniem na to ponownie. mój projekt polegał na narysowaniu dużej ilości wizualizacji, przy powyższym kodzie przepływ pracy został usprawniony.
Hualin
1

To działa dla mnie:

dla każdej serii użyj losowego generatora kolorów rgb

c = color[np.random.random_sample(), np.random.random_sample(), np.random.random_sample()]
bracoo
źródło
Nie wiem jaki jest Twój zmienny kolor, ale przy użyciu podejścia możliwe jest zrobić coś takiego: plt.scatter(your values to the graph, color= (np.random.random_sample(), np.random.random_sample(), np.random.random_sample()) ). Wspomniałeś o generatorze RGB i zadeklarowałeś listę RGB, generatory są zadeklarowane między '()'
Joel Carneiro
0

DUŻO szybszym rozwiązaniem w przypadku dużego zbioru danych i ograniczonej liczby kolorów jest użycie Pand i funkcji grupowania:

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()
MdM
źródło