2012-08-13 197 views
46

Acabo de empezar a usar pandas/matplotlib como reemplazo de Excel para generar gráficos de barras apiladas. Me encuentro con un problemaCómo dar un gráfico de barras pandas/matplotlib colores personalizados

(1) solo hay 5 colores en el mapa de colores predeterminado, por lo que si tengo más de 5 categorías, los colores se repiten. ¿Cómo puedo especificar más colores? Idealmente, ¿un degradado con un color inicial y un color final, y una forma de generar dinámicamente n colores entre ellos?

(2) los colores no son muy agradables a la vista. ¿Cómo especifico un conjunto personalizado de n colores? O bien, un degradado también funcionaría.

Un ejemplo que ilustra los dos puntos anteriores es el siguiente:

4 from matplotlib import pyplot 
    5 from pandas import * 
    6 import random 
    7 
    8 x = [{i:random.randint(1,5)} for i in range(10)] 
    9 df = DataFrame(x) 
10 
11 df.plot(kind='bar', stacked=True) 

y la salida es la siguiente:

enter image description here

+0

Existe una manera bastante fácil de conseguir un mapa de colores parcial. [Ver esta solución a continuación] (https://stackoverflow.com/a/47146928/3707607) –

Respuesta

69

Puede especificar la opción color como una lista directamente a la plot función.

from matplotlib import pyplot as plt 
from itertools import cycle, islice 
import pandas, numpy as np # I find np.random.randint to be better 

# Make the data 
x = [{i:np.random.randint(1,5)} for i in range(10)] 
df = pandas.DataFrame(x) 

# Make a list by cycling through the colors you care about 
# to match the length of your data. 
my_colors = list(islice(cycle(['b', 'r', 'g', 'y', 'k']), None, len(df))) 

# Specify this list of colors as the `color` option to `plot`. 
df.plot(kind='bar', stacked=True, color=my_colors) 

Para definir su propia lista personalizada, puede hacer algunas de las siguientes, o simplemente mirar hacia arriba las técnicas matplotlib para definir un elemento de color por sus valores RGB, etc. Usted puede conseguir tan complicado como usted desea con este.

my_colors = ['g', 'b']*5 # <-- this concatenates the list to itself 5 times. 
my_colors = [(0.5,0.4,0.5), (0.75, 0.75, 0.25)]*5 # <-- make two custom RGBs and repeat/alternate them over all the bar elements. 
my_colors = [(x/10.0, x/20.0, 0.75) for x in range(len(df))] # <-- Quick gradient example along the Red/Green dimensions. 

El último ejemplo se obtiene el seguimiento simple gradiente de colores para mí:

enter image description here

no jugaba con el tiempo suficiente para encontrar la manera de forzar la leyenda para recoger el colores definidos, pero estoy seguro de que puedes hacerlo.

En general, sin embargo, un gran consejo es usar las funciones de Matplotlib directamente. Llamarlos desde Pandas está bien, pero encuentro que obtienes mejores opciones y rendimiento llamándolos directamente desde Matplotlib.

+3

Error menor: my_colors = [cycle (['b', 'r', 'g', 'y', 'k'] ]). next() para i en rango (len (df))] dará 'b' cada vez en python 2.7. Debería usar list (islice (cycle (['b', 'r', 'g', 'y', 'k']), None, len (df))). – vkontori

+0

Gracias, probablemente no habría captado eso. Otra opción es crear el ciclo primero, luego simplemente llamar a su función 'siguiente' dentro de la comprensión. – ely

+0

Sí. it = cycle (['b', 'r', 'g', 'y', 'k']); my_colors = [next (it) for i in xrange (len (df))] lo cortaría también ... – vkontori

26

He encontrado la manera más fácil es utilizar el parámetro colormap en .plot() con uno de los gradientes de color predefinidos:

df.plot(kind='bar', stacked=True, colormap='Paired') 

enter image description here

Usted puede encontrar un gran list of preset colormaps here.

colormaps

1

Para una respuesta más detallada sobre cómo crear sus propios mapas de colores, le recomiendo visitar this page

Si la respuesta es demasiado trabajo, puede rápidamente hacer su propia lista de colores y pasarlos a el parámetro color. Todos los mapas de color están en el módulo matplotlib cm. Vamos a obtener una lista de 30 valores de color RGB (más alfa) del mapa de color del infierno invertido. Para hacerlo, primero obtenga el mapa de colores y páselo una secuencia de valores entre 0 y 1. Aquí, usamos np.linspace para crear 30 valores igualmente espaciados entre .4 y .8 que representan esa porción del mapa de colores.

from matplotlib import cm 
color = cm.inferno_r(np.linspace(.4,.8, 30)) 
color 

array([[ 0.865006, 0.316822, 0.226055, 1.  ], 
     [ 0.851384, 0.30226 , 0.239636, 1.  ], 
     [ 0.832299, 0.283913, 0.257383, 1.  ], 
     [ 0.817341, 0.270954, 0.27039 , 1.  ], 
     [ 0.796607, 0.254728, 0.287264, 1.  ], 
     [ 0.775059, 0.239667, 0.303526, 1.  ], 
     [ 0.758422, 0.229097, 0.315266, 1.  ], 
     [ 0.735683, 0.215906, 0.330245, 1.  ], 
     ..... 

entonces podemos usar este para trazar - utilizando los datos de la publicación original:

import random 
x = [{i:random.randint(1,5)} for i in range(30)] 
df = pd.DataFrame(x) 
df.plot(kind='bar', stacked=True, color=color, legend=False, figsize=(12,4)) 

enter image description here

Cuestiones relacionadas