Jak nadać wykresowi słupkowemu pandy / matplotlib niestandardowe kolory


85

Właśnie zacząłem używać pandas / matplotlib jako zamiennika programu Excel do generowania skumulowanych wykresów słupkowych. Mam problem

(1) w domyślnej mapie kolorów jest tylko 5 kolorów, więc jeśli mam więcej niż 5 kategorii, kolory się powtarzają. Jak mogę określić więcej kolorów? Idealnie, gradient z kolorem początkowym i końcowym oraz sposób na dynamiczne generowanie n kolorów pomiędzy nimi?

(2) kolory nie są zbyt przyjemne wizualnie. Jak określić niestandardowy zestaw n kolorów? Lub też zadziałałby gradient.

Przykład ilustrujący oba powyższe punkty znajduje się poniżej:

  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)

A wynik jest taki:

wprowadź opis obrazu tutaj


Istnieje dość łatwy sposób na uzyskanie częściowej mapy kolorów. Zobacz to rozwiązanie poniżej
Ted Petrou,

Odpowiedzi:


118

Możesz określić coloropcję jako listę bezpośrednio dla plotfunkcji.

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)

Aby zdefiniować własną listę niestandardową, możesz wykonać kilka następujących czynności lub po prostu sprawdzić techniki Matplotlib służące do definiowania elementu koloru za pomocą wartości RGB itp. Możesz to zrobić tak skomplikowane, jak chcesz.

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.

Ostatni przykład daje mi następujący prosty gradient kolorów:

wprowadź opis obrazu tutaj

Nie bawiłem się nim wystarczająco długo, aby wymyślić, jak zmusić legendę do wybrania określonych kolorów, ale jestem pewien, że możesz to zrobić.

Ogólnie rzecz biorąc, ważną radą jest po prostu bezpośrednie użycie funkcji z Matplotlib. Dzwonienie do nich z Pandas jest w porządku, ale uważam, że masz lepsze opcje i wydajność dzwoniąc do nich bezpośrednio z Matplotlib.


3
Drobny błąd: my_colors = [cycle (['b', 'r', 'g', 'y', 'k']). Next () for i in range (len (df))] da 'b' za każdym razem w Pythonie 2.7. Zamiast tego powinieneś użyć list (islice (cycle (['b', 'r', 'g', 'y', 'k']), None, len (df))).
vkontori

Dzięki, prawdopodobnie bym tego nie złapał. Inną opcją jest najpierw utworzenie cyklu, a następnie wywołanie jego nextfunkcji w zrozumieniu.
ely

Tak. it = cykl (['b', 'r', 'g', 'y', 'k']); my_colors = [next (it) for i in xrange (len (df))] również to wyciął ...
vkontori

1
Po zainstalowaniu pand i matplotlib powyższy kod nic dla mnie nie generuje, chociaż działa.
kakyo,

@kakyo Czy używasz zwykłego interpretera, IPythona lub powłoki (lub czegoś innego)? W zależności od typu środowiska, w którym wykonujesz ten kod, może być konieczne włączenie trybu interaktywnego dla matplotlib lub ustawienie pylab.ion()interaktywnego pylab.
ely


15

Aby uzyskać bardziej szczegółową odpowiedź na temat tworzenia własnych map kolorów, gorąco zachęcam do odwiedzenia tej strony

Jeśli ta odpowiedź jest zbyt pracochłonna, możesz szybko stworzyć własną listę kolorów i przekazać je do colorparametru. Wszystkie cmmapy kolorów znajdują się w module matplotlib. Zdobądźmy listę 30 wartości kolorów RGB (plus alfa) z mapy kolorów odwróconego piekła. Aby to zrobić, najpierw pobierz mapę kolorów, a następnie przekaż jej sekwencję wartości od 0 do 1. Tutaj używamy np.linspacedo utworzenia 30 równo rozmieszczonych wartości między .4 a .8, które reprezentują tę część mapy kolorów.

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

Następnie możemy użyć tego do wykreślenia, używając danych z oryginalnego postu:

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

wprowadź opis obrazu tutaj


2
Oto dokumentacja do innych map kolorów oprócz inferno_r: matplotlib.org/examples/color/colormaps_reference.html
tsando

1
Poszedłem za tym fragmentem, ale moja tablica kolorów zawsze ma te same wartości.
FaCoffee
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.