Mengatur warna berbeda untuk setiap seri di sebar plot di matplotlib

162

Misalkan saya memiliki tiga set data:

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

Saya dapat menyebarkan plot ini:

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

Bagaimana saya bisa melakukan ini dengan 10 set?

Saya mencari ini dan dapat menemukan referensi apa pun yang saya minta.

Edit: mengklarifikasi (semoga) pertanyaan saya

Jika saya memanggil pencar beberapa kali, saya hanya dapat mengatur warna yang sama pada setiap pencar. Juga, saya tahu saya bisa mengatur array warna secara manual tapi saya yakin ada cara yang lebih baik untuk melakukan ini. Pertanyaan saya kemudian, "Bagaimana saya bisa secara otomatis menyebarkan-set beberapa set data saya, masing-masing dengan warna yang berbeda.

Jika itu membantu, saya dapat dengan mudah menetapkan nomor unik untuk setiap kumpulan data.

Yotam
sumber
1
Apa pertanyaannya di sini? Warna juga bisa menjadi array, tetapi apa yang tidak bisa Anda pecahkan hanya dengan memanggil sebar beberapa kali?
seberg
1
Jika saya memanggil pencar beberapa kali, saya mendapatkan warna yang sama. Saya akan memperbarui pertanyaan saya.
Yotam

Jawaban:

269

Saya tidak tahu apa yang Anda maksud dengan 'secara manual'. Anda dapat memilih colourmap dan membuat array warna dengan cukup mudah:

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)

Grafik matplotlib dengan warna berbeda

Atau Anda dapat membuat pengendara sepeda warna Anda sendiri menggunakan itertools.cycledan menentukan warna yang ingin Anda putar, gunakan nextuntuk mendapatkan yang Anda inginkan. Misalnya, dengan 3 warna:

import itertools

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

Grafik matplotlib dengan hanya 3 warna

Kalau dipikir-pikir, mungkin lebih bersih tidak digunakan zipdengan yang pertama juga:

colors = iter(cm.rainbow(np.linspace(0, 1, len(ys))))
for y in ys:
    plt.scatter(x, y, color=next(colors))
DSM
sumber
1
+1. Siklus itertools mungkin bukan ide yang baik dalam situasi ini, karena itu akan berakhir dengan beberapa dataset memiliki warna yang sama.
David Robinson
1
@ DavidVobinson: tidak jika Anda menentukan semua sepuluh, meskipun saya setuju bersepeda semacam mengalahkan tujuan di sana ..: ^)
DSM
Tepatnya - maka itu bukan siklus :)
David Robinson
4
@ Macrocosme: bekerja untuk saya. Menambahkan plt.legend(['c{}'.format(i) for i in range(len(ys))], loc=2, bbox_to_anchor=(1.05, 1), borderaxespad=0., fontsize=11)ke bagian bawah di atas memberi saya legenda dengan warna.
DSM
solusi itertools sangat bagus ketika Anda ingin menghindari beberapa warna. Dalam kasus saya karena latar belakangnya hitam, saya ingin menghindari hitam.
Fabrizio
50

Cara normal untuk memplot plot dengan titik dalam warna berbeda di matplotlib adalah dengan memberikan daftar warna sebagai parameter.

Misalnya:

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

3 warna

Ketika Anda memiliki daftar daftar dan Anda ingin mereka diwarnai per daftar. Saya pikir cara yang paling elegan adalah yang disarankan oleh @DSM, cukup lakukan satu lingkaran membuat beberapa panggilan untuk tersebar.

Tetapi jika karena alasan tertentu Anda ingin melakukannya hanya dengan satu panggilan, Anda dapat membuat daftar warna yang besar, dengan pemahaman daftar dan sedikit pembagian lantai:

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)

Semua diplot

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
sumber
19

Perbaikan yang mudah

Jika Anda hanya memiliki satu jenis koleksi (mis. Pencar tanpa bilah kesalahan), Anda juga dapat mengubah warna setelah memplotnya, terkadang ini lebih mudah dilakukan.

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)

Satu-satunya bagian dari kode yang Anda butuhkan:

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

Outputnya memberi Anda warna yang berbeda bahkan ketika Anda memiliki banyak plot pencar yang berbeda di subplot yang sama.

masukkan deskripsi gambar di sini

GM
sumber
itu bagus tapi bagaimana Anda misalnya menambahkan errorbar dengan warna yang sama dengan fungsi ini? @ GM
PEBKAC
1
Hai @ PEBKAC, terima kasih untuk menunjukkannya, saya sudah berusaha keras siang ini untuk membuatnya bekerja juga dalam kasus itu, tetapi saya tidak dapat menemukan solusi apa pun sehingga saya mengedit pertanyaan dan memperingatkan pengguna lain. Terima kasih!
GM
Hai @ GM, maaf saya memposting beberapa komentar sebelum menyelesaikan solusi, yang dijelaskan di sini: stackoverflow.com/q/51444364/7541421
PEBKAC
1
Saya menggunakan metode lain untuk menetapkan warna untuk setiap seri dalam sebaran plot. Sekarang berhasil, sayangnya saya tidak dapat melanjutkan dengan solusi elegan Anda ketika datang ke errorbars, masih saya sangat berterima kasih atas posting Anda yang sangat membantu! Bersulang!
PEBKAC
7

Anda selalu dapat menggunakan plot()fungsi seperti ini:

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

plot sebagai pencar tetapi berubah warna

Ophir Carmi
sumber
6

Pertanyaan ini agak sulit sebelum Jan 2013 dan matplotlib 1.3.1 (Agu 2013), yang merupakan versi stabil tertua yang dapat Anda temukan di situs web matpplotlib. Namun setelah itu cukup sepele.

Karena versi sekarang matplotlib.pylab.scatter penugasan dukungan: array string nama warna, array nomor float dengan peta warna, array RGB atau RGBA.

jawaban ini didedikasikan untuk hasrat tak berujung @ Oxinabox untuk memperbaiki versi 2013 diriku pada tahun 2015.


Anda memiliki dua opsi untuk menggunakan perintah pencar dengan beberapa warna dalam satu panggilan.

  1. sebagai pylab.scatterdukungan perintah gunakan array RGBA untuk melakukan warna apa pun yang Anda inginkan;

  2. kembali pada awal 2013, tidak ada cara untuk melakukannya, karena perintah hanya mendukung satu warna untuk seluruh koleksi titik pencar. Ketika saya sedang mengerjakan proyek 10000-line saya, saya mencari solusi umum untuk memotongnya. jadi sangat norak, tapi saya bisa melakukannya dalam bentuk, warna, ukuran dan transparan apa pun. Trik ini juga bisa diterapkan untuk menggambar jalur koleksi, koleksi garis ....

kode ini juga terinspirasi oleh kode sumber pyplot.scatter , saya hanya menduplikasi apa yang dilakukan pencar tanpa memicu untuk menggambar.

perintah pyplot.scattermengembalikan PatchCollectionObjek, dalam file "matplotlib / collections.py" variabel pribadi _facecolorsdi Collectionkelas dan metode set_facecolors.

jadi kapan pun Anda memiliki poin sebar untuk menggambar, Anda bisa melakukan ini:

# 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
sumber
jadi agak rumit untuk membaca dan pada 2013 saya menggunakan python selama 1 tahun. jadi mengapa orang ingin tahu bagaimana melakukannya? Setelah berhasil, saya tidak pernah repot untuk melihatnya lagi. proyek saya adalah menggambar banyak visualisasi, dengan kode di atas, alur kerja disederhanakan.
Hualin
1

Ini bekerja untuk saya:

untuk setiap seri, gunakan penghasil warna rgb acak

c = color[np.random.random_sample(), np.random.random_sample(), np.random.random_sample()]
bracoo
sumber
Aku tidak tahu apa yang variabel warna Anda, tetapi menggunakan pendekatan Anda adalah mungkin untuk melakukan sesuatu seperti: plt.scatter(your values to the graph, color= (np.random.random_sample(), np.random.random_sample(), np.random.random_sample()) ). Anda menyebutkan generator RGB dan menyatakan daftar RGB, generator dideklarasikan antara '()'
Joel Carneiro
0

Solusi JAUH lebih cepat untuk dataset besar dan jumlah warna terbatas adalah penggunaan Pandas dan fungsi 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()
MdM
sumber