Establecer un color diferente para cada serie en el diagrama de dispersión

10 minutos de lectura

Avatar de usuario de Yotam
Yotam

Supongamos que tengo tres conjuntos de datos:

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

Puedo diagrama de dispersión esto:

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

¿Cómo puedo hacer esto con 10 juegos?

Busqué esto y pude encontrar alguna referencia a lo que estoy preguntando.

Editar: aclarar (con suerte) mi pregunta

Si llamo a scatter varias veces, solo puedo establecer el mismo color en cada scatter. Además, sé que puedo configurar una matriz de colores manualmente, pero estoy seguro de que hay una mejor manera de hacerlo. Entonces, mi pregunta es: “¿Cómo puedo hacer un diagrama de dispersión automático de varios conjuntos de datos, cada uno con un color diferente?

Si eso ayuda, puedo asignar fácilmente un número único a cada conjunto de datos.

  • ¿Cuál es la pregunta aquí? El color también puede ser una matriz, pero ¿qué no se puede resolver simplemente llamando a la dispersión varias veces?

    – seberg

    2 de septiembre de 2012 a las 14:22

  • Si llamo a scatter varias veces, obtengo los mismos colores. Actualizaré mi pregunta.

    – Yotam

    2 de septiembre de 2012 a las 14:24

Avatar de usuario de DSM
DSM

No sé a qué te refieres con ‘manualmente’. Puede elegir un mapa de colores y hacer una matriz de colores con bastante facilidad:

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)

Gráfico de Matplotlib con diferentes colores.

O puede hacer su propio ciclador de color usando itertools.cycle y especificando los colores que desea repetir, usando next para conseguir el que quieres. Por ejemplo, con 3 colores:

import itertools

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

Gráfico de Matplotlib con solo 3 colores

Ahora que lo pienso, tal vez sea más limpio no usarlo zip con el primero tampoco:

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

  • +1. Sin embargo, un ciclo de itertools probablemente no sea una buena idea en esta situación, ya que terminaría con múltiples conjuntos de datos con el mismo color.

    –David Robinson

    02/09/2012 a las 14:40

  • @DavidRobinson: no si especifica los diez, aunque estoy de acuerdo en que el ciclismo anula el propósito allí… :^)

    – DSM

    2 de septiembre de 2012 a las 14:41

  • Precisamente, entonces no es un ciclo 🙂

    –David Robinson

    2 de septiembre de 2012 a las 14:42

  • @macrocosme: funciona para mí. agregando plt.legend(['c{}'.format(i) for i in range(len(ys))], loc=2, bbox_to_anchor=(1.05, 1), borderaxespad=0., fontsize=11) al fondo lo de arriba me da una leyenda con colores.

    – DSM

    07/04/2013 a las 19:15

  • la solución de itertools es genial cuando quieres evitar algunos colores. En mi caso como el fondo es negro quiero evitar el negro.

    – Fabricio

    17 de septiembre de 2013 a las 13:06

Enmarca el avatar de usuario de Catherine White
marcos catherine blanco

La forma normal de trazar parcelas con puntos en diferentes colores en matplotlib es pasar una lista de colores como parámetro.

P.ej:

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

3 colores

Cuando tienes una lista de listas y las quieres coloreadas por lista. Creo que la forma más elegante es la sugerida por @DSM, solo haz un ciclo haciendo múltiples llamadas para dispersar.

Pero si por alguna razón quisieras hacerlo con una sola llamada, puedes hacer una gran lista de colores, con una lista de comprensión y un poco de división de pisos:

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)

Todo trazado

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

  • Esto es realmente genial para un gráfico de dispersión en el que tengo datos diarios de qué tan grande es un archivo de texto, y si agregué menos de, digamos, 200 bytes, hago un punto rojo, pero de lo contrario es verde.

    – aschultz

    14 de julio de 2021 a las 16:07

Avatar de usuario de GM
GM

Una solución fácil

Si solo tiene un tipo de colecciones (por ejemplo, dispersión sin barras de error), también puede cambiar los colores después de haberlos trazado, esto a veces es más fácil de realizar.

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)

La única pieza de código que necesita:

#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


ax.legend(fontsize="small")

La salida le brinda diferentes colores incluso cuando tiene muchos diagramas de dispersión diferentes en el mismo subparcela.

ingrese la descripción de la imagen aquí

  • eso es genial, pero ¿cómo agregarías, por ejemplo, barras de error con el mismo color con esta función? @GM

    – PEBKAC

    20 de julio de 2018 a las 12:48


  • Hola @PEBKAC, gracias por señalarlo, me esforcé mucho esta tarde para que funcione también en ese caso, pero no pude encontrar ninguna solución, así que edité la pregunta y advertí a los otros usuarios. ¡Gracias!

    – GM

    20/07/2018 a las 15:00

  • Hola @GM, lo siento, publiqué algunos comentarios antes de finalizar la solución, que se describe aquí: stackoverflow.com/q/51444364/7541421

    – PEBKAC

    20/07/2018 a las 17:30

  • Usé otro método para asignar los colores de cada serie en un diagrama de dispersión. Ahora funciona, desafortunadamente no pude continuar con su solución elegante cuando se trataba de barras de error, ¡aún estoy muy agradecido por su publicación súper útil! ¡Salud!

    – PEBKAC

    20 de julio de 2018 a las 17:31

Avatar de usuario de Ophir Carmi
Ofir Carmi

Siempre puedes usar el plot() funcionar así:

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

trazar como dispersión pero cambia de color

Esta pregunta es un poco complicada antes de enero de 2013 y matplotlib 1.3.1 (agosto de 2013), que es la versión estable más antigua que puede encontrar en el sitio web de matpplotlib. Pero después de eso es bastante trivial.

Porque la versión actual de matplotlib.pylab.scatter asignación de soporte: matriz de cadena de nombre de color, matriz de número flotante con mapa de color, matriz de RGB o RGBA.

esta respuesta está dedicada a la pasión infinita de @Oxinabox por corregir la versión 2013 de mí mismo en 2015.


tiene dos opciones de usar el comando de dispersión con varios colores en una sola llamada.

  1. como pylab.scatter soporte de comando use matriz RGBA para hacer cualquier color que desee;

  2. a principios de 2013, no hay forma de hacerlo, ya que el comando solo admite un solo color para toda la colección de puntos de dispersión. Cuando estaba haciendo mi proyecto de 10000 líneas, descubrí una solución general para evitarlo. entonces es muy hortera, pero puedo hacerlo en cualquier forma, color, tamaño y transparente. este truco también podría aplicarse para dibujar una colección de rutas, una colección de líneas….

el código también está inspirado en el código fuente de pyplot.scattersolo dupliqué lo que hace la dispersión sin activarlo para dibujar.

El comando pyplot.scatter devolver un PatchCollection Objeto, en el archivo “matplotlib/collections.py” una variable privada _facecolors en Collection clase y un método set_facecolors.

así que cada vez que tenga puntos de dispersión para dibujar, puede hacer esto:

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

  • por lo que es un poco complicado de leer y en 2013 usé python durante 1 año. Entonces, ¿por qué la gente querría saber cómo hacerlo? después de hacerlo funcionar, nunca me molesto en mirarlo de nuevo. mi proyecto era dibujar mucha visualización, con el código anterior, el flujo de trabajo se simplificó.

    – Hualín

    18 de septiembre de 2015 a las 12:39


Avatar de usuario de MdM
MDM

Una solución MUCHO más rápida para grandes conjuntos de datos y un número limitado de colores es el uso de Pandas y la función 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()

  • por lo que es un poco complicado de leer y en 2013 usé python durante 1 año. Entonces, ¿por qué la gente querría saber cómo hacerlo? después de hacerlo funcionar, nunca me molesto en mirarlo de nuevo. mi proyecto era dibujar mucha visualización, con el código anterior, el flujo de trabajo se simplificó.

    – Hualín

    18 de septiembre de 2015 a las 12:39


Avatar de usuario de Pang
Angustia

Esto funciona para mí:

para cada serie, use un generador de color rgb aleatorio

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

  • No sé cuál es su variable de color, pero usando su enfoque es posible hacer algo como: plt.scatter(your values to the graph, color= (np.random.random_sample(), np.random.random_sample(), np.random.random_sample()) ). Mencionó un generador RGB y declaró una lista RGB, los generadores se declaran entre ‘()’

    – Joel Carneiro

    14 de enero de 2019 a las 15:52


¿Ha sido útil esta solución?