2012-08-13 11 views
46

Właśnie zacząłem używać pandas/matplotlib jako zamiennika dla Excela do generowania skumulowanych wykresów słupkowych. Występuje problemJak nadać pandom/matplotlib bar graph niestandardowe kolory

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

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

Przykładem, który ilustruje obu powyższych punktów jest 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 wyjście jest takie:

enter image description here

+0

Jest to dość łatwy sposób uzyskać częściową mapę kolorów. [Zobacz to rozwiązanie poniżej] (https://stackoverflow.com/a/47146928/3707607) –

Odpowiedz

69

Możesz określić opcję color jako listy bezpośrednio do Funkcja plot.

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żna zrobić kilka z następujących czynności lub po prostu patrzeć technik matplotlib definiowania kolorów przez element jego wartości RGB itp można uzyskać tak skomplikowane, jak chcesz z tym.

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 otrzymuje się śledzić prosty gradient kolorów dla mnie:

enter image description here

nie grałem z nim na tyle długo, aby dowiedzieć się, jak zmusić legendę odebrać zdefiniowane kolory, ale jestem pewien, że możesz to zrobić.

Ogólnie rzecz biorąc, dużą radą jest skorzystanie z funkcji bezpośrednio z Matplotlib. Dzwonienie do nich z Pand jest w porządku, ale widzę, że masz lepsze opcje i wydajność, wywołując je bezpośrednio z Matplotlib.

+3

Drobny błąd: my_colors = [cykl (['b', 'r', 'g', 'y', 'k' ]). next() dla i w zakresie (len (df))] da "b" za każdym razem w pythonie 2.7. Powinieneś użyć listy (islice (cycle (['b', 'r', 'g', 'y', 'k']), None, len (df))). – vkontori

+0

Dzięki, prawdopodobnie bym tego nie zauważył. Inną opcją jest najpierw stworzenie cyklu, a następnie wywołanie funkcji "next" w ramach rozumienia. – ely

+0

Yup. it = cycle (['b', 'r', 'g', 'y', 'k']); my_colors = [next (it) for i in xrange (len (df))] też by to wycięło ... – vkontori

26

znalazłem najprostszym sposobem jest użycie parametru colormap w .plot() z jednym z zaprogramowanych kolorów gradientów:

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

enter image description here

można znaleźć dużą list of preset colormaps here.

colormaps

1

Bardziej szczegółowe odpowiedzi na temat tworzenia własnych colormaps, Gorąco polecam odwiedzenie this page

Jeśli odpowiedź jest zbyt dużo pracy, można szybko stworzyć własną listę kolorów i przekazać je do parametr color. Wszystkie colormaps są w module matplotlib cm. Zdobądźmy listę 30 kolorów RGB (plus alfa) z odwróconej mapy kolorów inferno. Aby to zrobić, najpierw pobierz mapowanie kolorów i przeprowadź sekwencję wartości między 0 a 1. Tutaj używamy np.linspace, aby utworzyć 30 równomiernie rozmieszczonych wartości pomiędzy .4 i .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.  ], 
     ..... 

Wtedy możemy to wykorzystać do działki - wykorzystując dane 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)) 

enter image description here

Powiązane problemy