Установка другого цвета для каждой серии в точечной диаграмме на matplotlib


Предположим, у меня есть три набора данных:

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 комплектов?

Я искал это и мог найти любую ссылку на то, что я прошу.

Edit: уточнение (надеюсь) мой вопрос

Если я вызываю scatter несколько раз, я могу установить только один и тот же цвет на каждом scatter. Кроме того, я знаю, что могу установить цветовой массив вручную, но я уверен, что есть лучший способ сделать это. Мой вопрос тогда: "как я могу автоматически разбросать-построить несколько наборов данных, каждый с другим цветом.

Если это поможет, я могу легко присвоить уникальный номер для каждого набора данных.

6 108

6 ответов:

Я не знаю, что вы подразумеваете под "вручную". Вы можете выбрать цветовую карту и сделать цветовой массив достаточно легко:

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)

или сделайте свой собственный цветной Циклер с помощью itertools.cycle и указание цветов, которые вы хотите перебрать, используя next чтобы получить тот, который вы хотите. Например (мне лень набирать десять цветов):

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

подумайте об этом, может быть, это чище, чтобы не использовать zip С первым тоже:

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

[PS: Я действительно ненавижу, что я нужно отбросить 'u' при работе с matplotlib..]

обычный способ построения графиков с точками разных цветов в matplotlib-это передать список цветов в качестве параметра.

например:

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

3 colors

когда у вас есть список списков, и вы хотите, чтобы они были окрашены в список. Я думаю, что самый элегантный способ-это то, что предлагает @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)

All plotted

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

легко исправить

если у вас есть только один тип коллекций (например, разброс без полос ошибок), вы также можете изменить цвета после того, как вы построили их, это иногда легче выполнить.

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

выход дает вам разные цвета, даже если у вас есть много разных диаграмм рассеяния в одном подзаголовке.

enter image description here

этот вопрос немного сложнее до января 2013 года и matplotlib 1.3.1 (Aug 2013), который является самой старой стабильной версией, которую вы можете найти на веб-сайте matpplotlib. Но после этого это довольно тривиально.

потому что нынешний вариант matplotlib.pylab.scatter назначение поддержки: массив строки имени цвета, массив номера поплавка с картой цвета, массив РГБ или РГБА.

этот ответ посвящен бесконечной страсти @Oxinabox к исправлению версии 2013 года себя в 2015.


у вас есть два варианта использования команды scatter с несколькими цветами в одном вызове.

  1. как pylab.scatter поддержка команд используйте массив RGBA, чтобы сделать любой цвет, который вы хотите;

  2. еще в начале 2013 года, нет никакого способа сделать это, так как команда поддерживает только один цвет для всей коллекции точек рассеяния. Когда я делал свой проект 10000-line, я придумал общее решение, чтобы обойти его. так что это очень липкий, но я могу сделать это в любой форме, цвет, размер и прозрачный. этот трюк также может быть применен для рисования коллекции путей, коллекции линий....

код также вдохновлен исходным кодом pyplot.scatter, Я просто дублировал то, что scatter делает без триггера его рисовать.

команда pyplot.scatter возвратить PatchCollection объект, в файле "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()

вы всегда можете использовать

это работает для меня:

для каждой серии используйте генератор случайных цветов rgb

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