Đặt màu khác nhau cho từng chuỗi trong biểu đồ phân tán trên matplotlib


162

Giả sử tôi có ba bộ dữ liệu:

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

Tôi có thể phân tán âm mưu này:

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

Làm thế nào tôi có thể làm điều này với 10 bộ?

Tôi đã tìm kiếm cái này và có thể tìm thấy bất kỳ tài liệu tham khảo nào cho những gì tôi đang hỏi.

Chỉnh sửa: làm rõ (hy vọng) câu hỏi của tôi

Nếu tôi gọi phân tán nhiều lần, tôi chỉ có thể đặt cùng một màu trên mỗi phân tán. Ngoài ra, tôi biết tôi có thể thiết lập một mảng màu theo cách thủ công nhưng tôi chắc chắn có một cách tốt hơn để làm điều này. Câu hỏi của tôi là: "Làm thế nào tôi có thể tự động phân tán biểu đồ một số bộ dữ liệu của mình, mỗi bộ có một màu khác nhau.

Nếu điều đó có ích, tôi có thể dễ dàng gán một số duy nhất cho mỗi bộ dữ liệu.


1
Cái gì ở đây? Màu sắc cũng có thể là một mảng, nhưng những gì bạn không thể giải quyết chỉ bằng cách gọi phân tán nhiều lần?
seberg

1
Nếu tôi gọi phân tán nhiều lần, tôi sẽ có cùng màu. Tôi sẽ cập nhật câu hỏi của tôi.
Yotam

Câu trả lời:


269

Tôi không biết ý của bạn là 'thủ công'. Bạn có thể chọn một màu sắc và tạo một mảng màu đủ dễ dàng:

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)

Biểu đồ Matplotlib với các màu sắc khác nhau

Hoặc bạn có thể tạo itertools.cyclechu trình màu của riêng mình bằng cách sử dụng và chỉ định các màu bạn muốn lặp lại, sử dụng nextđể có được màu bạn muốn. Ví dụ: với 3 màu:

import itertools

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

Biểu đồ Matplotlib chỉ có 3 màu

Hãy nghĩ về nó, có lẽ nó không sạch hơn khi không sử dụng zipvới cái đầu tiên:

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

1
+1. Một chu trình itertools có lẽ không phải là một ý tưởng tốt trong tình huống này, vì nó sẽ kết thúc với nhiều bộ dữ liệu có cùng màu.
David Robinson

1
@DavidRobinson: không nếu bạn chỉ định tất cả mười, mặc dù tôi đồng ý loại xe đạp đánh bại mục đích ở đó ..: ^)
DSM

Chính xác- thì đó không phải là một chu kỳ :)
David Robinson

4
@macrocosme: làm việc cho tôi. Thêm plt.legend(['c{}'.format(i) for i in range(len(ys))], loc=2, bbox_to_anchor=(1.05, 1), borderaxespad=0., fontsize=11)vào phía dưới ở trên cho tôi một huyền thoại với màu sắc.
DSM

giải pháp itertools là tuyệt vời khi bạn muốn tránh một số màu sắc. Trong trường hợp của tôi vì nền là màu đen, tôi muốn tránh màu đen.
Fabrizio

50

Cách thông thường để vẽ đồ thị với các điểm có màu khác nhau trong matplotlib là truyền một danh sách các màu làm tham số.

Ví dụ:

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

3 màu

Khi bạn có một danh sách các danh sách và bạn muốn chúng được tô màu theo mỗi danh sách. Tôi nghĩ rằng cách thanh lịch nhất là suggesyted by @DSM, chỉ cần thực hiện một vòng lặp thực hiện nhiều cuộc gọi để phân tán.

Nhưng nếu vì lý do nào đó bạn muốn thực hiện nó chỉ bằng một cuộc gọi, bạn có thể tạo một danh sách lớn các màu sắc, với sự hiểu biết danh sách và một chút phân chia sàn:

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)

Tất cả âm mưu

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

Một sửa chữa dễ dàng

Nếu bạn chỉ có một loại bộ sưu tập (ví dụ: phân tán không có thanh lỗi), bạn cũng có thể thay đổi màu sau khi bạn đã vẽ chúng, điều này đôi khi dễ thực hiện hơn.

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)

Đoạn mã duy nhất mà bạn cần:

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

Đầu ra cung cấp cho bạn các màu khác nhau ngay cả khi bạn có nhiều ô phân tán khác nhau trong cùng một ô phụ.

nhập mô tả hình ảnh ở đây


Điều đó thật tuyệt nhưng làm thế nào bạn có thể thêm các lỗi có cùng màu với chức năng này? @GM
PEBKAC

1
Xin chào @PEBKAC, cảm ơn bạn đã chỉ ra, chiều nay tôi đã cố gắng làm cho nó hoạt động tốt trong trường hợp đó nhưng tôi không thể tìm thấy bất kỳ giải pháp nào nên tôi đã chỉnh sửa câu hỏi và cảnh báo cho những người dùng khác. Cảm ơn!
GM

Xin chào @GM, xin lỗi tôi đã đăng một vài bình luận trước khi hoàn thành giải pháp, được mô tả ở đây: stackoverflow.com/q/51444364/7541421
PEBKAC 20/07/18

1
Tôi đã sử dụng một phương pháp khác để gán màu cho mỗi chuỗi trong một biểu đồ phân tán. Bây giờ nó hoạt động, thật không may, tôi không thể tiến hành giải pháp tao nhã của bạn khi gặp lỗi, tôi vẫn rất biết ơn về bài đăng siêu hữu ích của bạn! Chúc mừng!
PEBKAC

7

Bạn luôn có thể sử dụng plot()chức năng như vậy:

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

cốt truyện như phân tán nhưng thay đổi màu sắc


6

Câu hỏi này hơi khó trước tháng 1 năm 2013 và matplotlib 1.3.1 (tháng 8 năm 2013), đây là phiên bản ổn định lâu đời nhất bạn có thể tìm thấy trên trang web matpplotlib. Nhưng sau đó thì khá tầm thường.

Bởi vì phiên bản hiện tại của việc matplotlib.pylab.scattergán hỗ trợ: mảng chuỗi tên màu, mảng số float với bản đồ màu, mảng RGB hoặc RGBA.

câu trả lời này được dành cho niềm đam mê bất tận của @ Oxinabox trong việc sửa lỗi phiên bản 2013 của tôi vào năm 2015.


bạn có hai tùy chọn sử dụng lệnh phân tán với nhiều màu trong một cuộc gọi.

  1. như pylab.scatterhỗ trợ lệnh sử dụng mảng RGBA để làm bất cứ màu gì bạn muốn;

  2. trở lại đầu năm 2013, không có cách nào để làm như vậy, vì lệnh chỉ hỗ trợ một màu duy nhất cho toàn bộ bộ sưu tập điểm phân tán. Khi tôi đang thực hiện dự án 10000 dòng của mình, tôi tìm ra một giải pháp chung để bỏ qua nó. Vì vậy, nó rất khó khăn, nhưng tôi có thể làm nó trong bất kỳ hình dạng, màu sắc, kích thước và trong suốt. Thủ thuật này cũng có thể được áp dụng để vẽ bộ sưu tập đường dẫn, bộ sưu tập dòng ....

mã cũng được lấy cảm hứng từ mã nguồn của pyplot.scatter, tôi chỉ sao chép những gì phân tán mà không kích hoạt nó để vẽ.

lệnh pyplot.scattertrả về một PatchCollectionObject, trong tệp "matplotlib / sưu tập" một biến riêng _facecolorstrong Collectionlớp và một phương thức set_facecolors.

vì vậy bất cứ khi nào bạn có một điểm phân tán để vẽ, bạn có thể làm điều này:

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

Vì vậy, nó khá phức tạp để đọc và năm 2013 tôi đã sử dụng python trong 1 năm. vậy tại sao mọi người lại muốn biết làm thế nào? Sau khi làm cho nó hoạt động, tôi không bao giờ bận tâm để nhìn lại nó. Dự án của tôi là vẽ rất nhiều hình ảnh, với đoạn mã trên, luồng công việc đã được sắp xếp hợp lý.
Hualin

1

Điều này làm việc cho tôi:

Đối với mỗi loạt, sử dụng một trình tạo màu rgb ngẫu nhiên

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

Tôi không biết biến màu của bạn là gì, nhưng sử dụng cách tiếp cận của bạn, có thể thực hiện một số thứ như : plt.scatter(your values to the graph, color= (np.random.random_sample(), np.random.random_sample(), np.random.random_sample()) ). Bạn đã đề cập đến một trình tạo RGB và bạn đã khai báo danh sách RGB, các trình tạo được khai báo giữa '()'
Joel Carneiro

0

Một giải pháp nhanh hơn NHIỀU cho tập dữ liệu lớn và số lượng màu hạn chế là sử dụng Pandas và chức năng nhóm:

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()
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.