การตั้งค่าสีที่แตกต่างสำหรับแต่ละชุดในพล็อตกระจายบน 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
quesiton คืออะไรที่นี่? สีสามารถเป็นอาร์เรย์ได้เช่นกัน แต่สิ่งใดที่คุณไม่สามารถแก้ไขได้ด้วยการเรียกการกระจายหลาย ๆ ครั้ง?
seberg

1
ถ้าฉันโทรกระจายหลายครั้งฉันจะได้สีเดียวกัน ฉันจะอัปเดตคำถามของฉัน
Yotam

คำตอบ:


269

ฉันไม่ทราบว่าคุณหมายถึงอะไรด้วยตนเอง คุณสามารถเลือก colourmap และสร้างอาร์เรย์สีได้ง่ายพอ:

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 อาจไม่ใช่ความคิดที่ดีในสถานการณ์เช่นนี้เนื่องจากมันจะจบลงด้วยชุดข้อมูลหลายชุดที่มีสีเดียวกัน
David Robinson

1
@DavidRobinson: ไม่ได้ถ้าคุณระบุทั้งสิบแม้ว่าฉันยอมรับการขี่จักรยานประเภทของการเอาชนะวัตถุประสงค์ที่นั่น .. : ^)
DSM

แม่นยำ - ไม่ใช่วัฏจักร :)
David Robinson

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 นั้นยอดเยี่ยมเมื่อคุณต้องการหลีกเลี่ยงบางสี ในกรณีของฉันเนื่องจากพื้นหลังเป็นสีดำฉันต้องการหลีกเลี่ยงสีดำ
Fabrizio

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
PEBKAC

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 ของฉันในปี 2558


คุณมีสองตัวเลือกในการใช้คำสั่งกระจายที่มีหลายสีในการโทรครั้งเดียว

  1. ในฐานะpylab.scatterผู้สนับสนุนคำสั่งให้ใช้อาร์เรย์ RGBA เพื่อทำสีที่คุณต้องการ

  2. ย้อนกลับไปในต้นปี 2013 ไม่มีวิธีการทำเช่นนี้เนื่องจากคำสั่งสนับสนุนเฉพาะสีเดียวสำหรับการรวบรวมจุดกระจายทั้งหมด เมื่อฉันทำโครงการ 10,000 บรรทัดของฉันฉันจะหาทางออกทั่วไปเพื่อหลีกเลี่ยงมัน ดังนั้นมันไม่มีรสนิยมที่ดีมาก แต่ฉันสามารถทำในสิ่งที่รูปร่างสีขนาดและโปร่งใส เคล็ดลับนี้ยังสามารถนำไปใช้วาดคอลเลกชันเส้นทางการรวบรวมบรรทัด ....

รหัสยังได้รับแรงบันดาลใจจากซอร์สโค้ดของpyplot.scatterฉันเพิ่งทำซ้ำสิ่งที่กระจายโดยไม่เรียกให้วาด

คำสั่งpyplot.scatterส่งคืนPatchCollectionวัตถุในแฟ้ม "matplotlib / collections.py" ตัวแปรส่วนตัว_facecolorsในชั้นเรียนและวิธีการCollectionset_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 ปี ดังนั้นทำไมผู้คนต้องการทราบวิธีการทำ หลังจากใช้งานได้ฉันไม่เคยสนใจที่จะดูอีกครั้ง โครงการของฉันคือการสร้างภาพข้อมูลจำนวนมากด้วยโค้ดด้านบนกระบวนการทำงานก็คล่องตัวขึ้น
Hualin

1

สิ่งนี้ใช้ได้กับฉัน:

สำหรับแต่ละชุดให้ใช้ตัวสร้างสี rgb แบบสุ่ม

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 เครื่องกำเนิดไฟฟ้าจะประกาศระหว่าง '()'
Joel Carneiro

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()
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.