2012-08-13 1 views
46

Ho appena iniziato a utilizzare pandas/matplotlib come sostituto di Excel per generare grafici a barre in pila. Sto riscontrando un problemaCome assegnare un grafico a barre a colori Panda/Matplotlib

(1) ci sono solo 5 colori nella mappa colori di default, quindi se ho più di 5 categorie, i colori si ripetono. Come posso specificare più colori? Idealmente, una sfumatura con un colore iniziale e un colore finale e un modo per generare dinamicamente n colori in mezzo?

(2) i colori non sono molto visivamente gradevoli. Come posso specificare un set personalizzato di n colori? Oppure funzionerebbe anche un gradiente.

Un esempio che illustra entrambi i punti di cui sopra è qui sotto:

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) 

e l'uscita è questa:

enter image description here

+0

C'è un modo abbastanza facile ottenere una colormap parziale. [Vedi questa soluzione sotto] (https://stackoverflow.com/a/47146928/3707607) –

risposta

69

È possibile specificare l'opzione color come una lista direttamente al plot funzione.

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) 

Per definire il proprio elenco personalizzato, si può fare un paio di quanto segue, o semplicemente cercare le tecniche matplotlib per la definizione di un elemento di colore dai suoi valori RGB, ecc È possibile ottenere così complicato come si desidera con questo.

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. 

L'ultimo esempio produce il seguire semplice gradiente di colori per me:

enter image description here

non ho giocato con esso abbastanza a lungo per capire come forzare la leggenda di prendere il colori definiti, ma sono sicuro che puoi farlo.

In generale, tuttavia, un grande consiglio è quello di utilizzare direttamente le funzioni direttamente da Matplotlib. Chiamarli da Pandas è OK, ma trovo che ottieni migliori opzioni e prestazioni chiamandoli direttamente da Matplotlib.

+3

Insetto minore: my_colors = [ciclo (['b', 'r', 'g', 'y', 'k' ]). next() per i in range (len (df))] darà 'b' ogni volta in python 2.7. Dovresti usare list (islice (cycle (['b', 'r', 'g', 'y', 'k']), None, len (df))). – vkontori

+0

Grazie, probabilmente non l'avrei capito. Un'altra opzione è quella di creare prima il ciclo, quindi chiamare la sua funzione 'next' nella comprensione. – ely

+0

Sì. it = cycle (['b', 'r', 'g', 'y', 'k']); my_colors = [next (it) per i in xrange (len (df))] lo taglierebbe pure ... – vkontori

26

Ho trovato il modo più semplice è quello di utilizzare il parametro colormap in .plot() con una delle sfumature di colore preimpostati:

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

enter image description here

Si può trovare un gran list of preset colormaps here.

colormaps

1

Per una risposta più dettagliata sulla creazione di mappe di colori, consiglio vivamente a visitare this page

Se la risposta è troppo lavoro, è possibile effettuare rapidamente la vostra lista di colori e passarli a il parametro color. Tutte le mappe colori sono nel modulo matplotlib cm. Otteniamo una lista di 30 valori di colore RGB (più alpha) dalla colormap inversa invertita. Per fare ciò, prima prendi la mappa di colori e passa una sequenza di valori tra 0 e 1. Qui, usiamo np.linspace per creare 30 valori equidistanti tra .4 e .8 che rappresentano quella porzione della mappa di colori.

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.  ], 
     ..... 

Poi possiamo usare questo per tracciare - utilizzando i dati dal post originale:

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