Come dare colori personalizzati a un grafico a barre panda / matplotlib


86

Ho appena iniziato a utilizzare panda / matplotlib in sostituzione di Excel per generare grafici a barre in pila. Sto riscontrando un problema

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

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

Di seguito è riportato un esempio che illustra entrambi i punti precedenti:

  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'output è questo:

inserisci qui la descrizione dell'immagine


C'è un modo abbastanza semplice per ottenere una mappa dei colori parziale. Vedi questa soluzione di seguito
Ted Petrou

Risposte:


120

È possibile specificare l' coloropzione come elenco direttamente nella plotfunzione.

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 tuo elenco personalizzato, puoi eseguire alcune delle seguenti operazioni, o semplicemente cercare le tecniche Matplotlib per definire un elemento di colore in base ai suoi valori RGB, ecc. Puoi complicare quanto vuoi 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 restituisce il seguente semplice gradiente di colori per me:

inserisci qui la descrizione dell'immagine

Non ci ho giocato abbastanza a lungo per capire come forzare la leggenda a raccogliere i colori definiti, ma sono sicuro che puoi farlo.

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


3
Bug minore: my_colors = [cycle (['b', 'r', 'g', 'y', 'k']). Next () for 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

Grazie, probabilmente non l'avrei capito. Un'altra opzione è creare prima il ciclo, quindi chiamare la sua nextfunzione all'interno della comprensione.
ely

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

1
Con panda e matplotlib installati oggi, il codice sopra non genera nulla per me, anche se funziona.
kakyo

@kakyo Sei in esecuzione nell'interprete normale, IPython o dalla shell (o qualcos'altro)? A seconda del tipo di ambiente in cui si esegue questo codice, potrebbe essere necessario attivare la modalità interattiva per matplotlib o impostare pylab.ion()per pylab interattivo.
ely


15

Per una risposta più dettagliata sulla creazione delle proprie mappe di colori, consiglio vivamente di visitare questa pagina

Se la risposta è troppo faticosa, puoi creare rapidamente il tuo elenco di colori e passarli al colorparametro. Tutte le mappe di colori sono nel cmmodulo matplotlib. Otteniamo un elenco di 30 valori di colore RGB (più alfa) dalla mappa dei colori dell'inferno invertita. Per fare ciò, prima prendi la mappa dei colori e poi passagli una sequenza di valori tra 0 e 1. Qui, usiamo np.linspaceper creare 30 valori equidistanti tra .4 e .8 che rappresentano quella parte della mappa dei 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.      ],
       .....

Quindi possiamo usarlo per tracciare, utilizzando i dati del 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))

inserisci qui la descrizione dell'immagine


2
Ecco la documentazione per altre mappe di colori oltre a inferno_r: matplotlib.org/examples/color/colormaps_reference.html
tsando

1
Ho seguito questo frammento ma il mio array di colori ha sempre gli stessi valori.
FaCoffee
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.