Jak uzyskać różne kolorowe linie dla różnych wykresów na jednej figurze?

202

Używam matplotlibdo tworzenia fabuł. Muszę zidentyfikować każdy wykres innym kolorem, który powinien zostać automatycznie wygenerowany przez Python.

Czy możesz mi podać metodę umieszczania różnych kolorów dla różnych wykresów na tej samej figurze?

pottigopi
źródło

Odpowiedzi:

424

Matplotlib robi to domyślnie.

Na przykład:

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

plt.plot(x, x)
plt.plot(x, 2 * x)
plt.plot(x, 3 * x)
plt.plot(x, 4 * x)
plt.show()

Podstawowa fabuła pokazująca cykliczne zmiany kolorów

Jak już zapewne wiesz, możesz łatwo dodać legendę:

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

plt.plot(x, x)
plt.plot(x, 2 * x)
plt.plot(x, 3 * x)
plt.plot(x, 4 * x)

plt.legend(['y = x', 'y = 2x', 'y = 3x', 'y = 4x'], loc='upper left')

plt.show()

Podstawowa fabuła z legendą

Jeśli chcesz kontrolować kolory, które będą przełączane:

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(10)

plt.gca().set_color_cycle(['red', 'green', 'blue', 'yellow'])

plt.plot(x, x)
plt.plot(x, 2 * x)
plt.plot(x, 3 * x)
plt.plot(x, 4 * x)

plt.legend(['y = x', 'y = 2x', 'y = 3x', 'y = 4x'], loc='upper left')

plt.show()

Wykres pokazujący kontrolę nad domyślnym przełączaniem kolorów

Jeśli nie znasz Matplotlib, samouczek jest dobrym miejscem do rozpoczęcia .

Edytować:

Po pierwsze, jeśli masz dużo (> 5) rzeczy, które chcesz narysować na jednej figurze, albo:

  1. Umieść je na różnych wykresach (rozważ użycie kilku podplotów na jednej figurze) lub
  2. Użyj czegoś innego niż kolor (np. Style znaczników lub grubość linii), aby je rozróżnić.

W przeciwnym razie skończysz z bardzo niechlujną fabułą! Bądź miły dla każdego, kto kiedykolwiek przeczyta cokolwiek robisz i nie próbuj wrzucać 15 różnych rzeczy do jednej postaci !!

Poza tym wiele osób jest w różnym stopniu ślepych na kolory, a rozróżnienie między wieloma subtelnie różnymi kolorami jest trudniejsze dla większej liczby osób, niż możesz sobie wyobrazić.

To powiedziawszy, jeśli naprawdę chcesz umieścić 20 linii na jednej osi w 20 stosunkowo różnych kolorach, oto jeden ze sposobów, aby to zrobić:

import matplotlib.pyplot as plt
import numpy as np

num_plots = 20

# Have a look at the colormaps here and decide which one you'd like:
# http://matplotlib.org/1.2.1/examples/pylab_examples/show_colormaps.html
colormap = plt.cm.gist_ncar
plt.gca().set_prop_cycle(plt.cycler('color', plt.cm.jet(np.linspace(0, 1, num_plots))))

# Plot several different functions...
x = np.arange(10)
labels = []
for i in range(1, num_plots + 1):
    plt.plot(x, i * x + 5 * i)
    labels.append(r'$y = %ix + %i$' % (i, 5*i))

# I'm basically just demonstrating several different legend options here...
plt.legend(labels, ncol=4, loc='upper center', 
           bbox_to_anchor=[0.5, 1.1], 
           columnspacing=1.0, labelspacing=0.0,
           handletextpad=0.0, handlelength=1.5,
           fancybox=True, shadow=True)

plt.show()

Unikalne kolory dla 20 linii na podstawie danej mapy kolorów

Joe Kington
źródło
17
Zwróć uwagę na ostatni przykład, w nowszych wersjach matplotlib, set_color_cyclejest on przestarzały, więc ta linia powinna być plt.gca().set_prop_cycle(plt.cycler('color', plt.cm.jet(np.linspace(0, 1, num_plots))))i po prostu zmień ją plt.cm.YOUR_PREFERED_COLOR_MAPw zależności od potrzeb.
Nate
1
@JoeKington: Wyjaśnienie było wspaniałe, bardzo dziękuję
Rika
to jest świetne. czy istnieje sposób na uczynienie ich interaktywnymi? na przykład w RI przekonwertuj ggplot na ggplotly (), a wykres stanie się interaktywny HTML
kRazzy R
Jestem przekonany, że OP wiedział, że Matplotlib koloruje odpowiednio różne krzywe na jednym wykresie (w jednym axes) i zapytał o zmianę koloru pojedynczej linii na różnych wykresach (różne axes) ... To powiedziawszy, doskonała odpowiedź na ważne pytanie (być może inne niż to, które zadał OP, ale nikt nie może powiedzieć, ponieważ zadali to jedno pytanie i zniknęło!) - +1
gboffi
37

Ustawianie ich później

Jeśli nie znasz liczby działek, które zamierzasz wydrukować, możesz zmienić kolory po ich wykreśleniu, pobierając liczbę bezpośrednio z wykresu .lines, używając tego rozwiązania:

Niektóre losowe dane

import matplotlib.pyplot as plt
import numpy as np

fig1 = plt.figure()
ax1 = fig1.add_subplot(111)


for i in range(1,15):
    ax1.plot(np.array([1,5])*i,label=i)

Potrzebny fragment kodu:

colormap = plt.cm.gist_ncar #nipy_spectral, Set1,Paired   
colors = [colormap(i) for i in np.linspace(0, 1,len(ax1.lines))]
for i,j in enumerate(ax1.lines):
    j.set_color(colors[i])
  

ax1.legend(loc=2)

Wynik jest następujący:wprowadź opis zdjęcia tutaj

GM
źródło
8

TL; DR Nie, nie można tego zrobić automatycznie . Tak to mozliwe.

import matplotlib.pyplot as plt
my_colors = plt.rcParams['axes.prop_cycle']() # <<< note that we CALL the prop_cycle
fig, axes = plt.subplots(2,3)
for ax in axes.flatten(): ax.plot((0,1), (0,1), **next(my_colors))

wprowadź opis zdjęcia tutaj Każdy wykres ( axes) na rysunku ( figure) ma swój własny cykl kolorów - jeśli nie wymusisz innego koloru dla każdego wykresu, wszystkie wykresy mają tę samą kolejność kolorów, ale jeśli rozciągniemy nieco, co oznacza „automatycznie” , to może być zrobione.


OP napisał

[...] Muszę zidentyfikować każdy wykres innym kolorem, który powinien zostać automatycznie wygenerowany przez [Matplotlib].

Ale ... Matplotlib automatycznie generuje różne kolory dla każdej innej krzywej

In [10]: import numpy as np
    ...: import matplotlib.pyplot as plt

In [11]: plt.plot((0,1), (0,1), (1,2), (1,0));
Out[11]:

wprowadź opis zdjęcia tutaj

Dlaczego więc wniosek OP? Jeśli nadal czytamy, to mamy

Czy możesz mi podać metodę umieszczania różnych kolorów dla różnych wykresów na tej samej figurze?

i ma to sens, ponieważ każda fabuła (każda axesw języku Matplotlib) ma swoją color_cycle(a raczej w 2018 r. swoją prop_cycle), a każda fabuła ( axes) ponownie używa tych samych kolorów w tej samej kolejności.

In [12]: fig, axes = plt.subplots(2,3)

In [13]: for ax in axes.flatten():
    ...:     ax.plot((0,1), (0,1))

wprowadź opis zdjęcia tutaj

Jeśli takie jest znaczenie pierwotnego pytania, jedną z możliwości jest wyraźne nazwanie innego koloru dla każdej działki.

Jeśli wykresy (jak to często bywa) są generowane w pętli, musimy mieć dodatkową zmienną pętli, aby zastąpić kolor automatycznie wybrany przez Matplotlib.

In [14]: fig, axes = plt.subplots(2,3)

In [15]: for ax, short_color_name in zip(axes.flatten(), 'brgkyc'):
    ...:     ax.plot((0,1), (0,1), short_color_name)

wprowadź opis zdjęcia tutaj

Inną możliwością jest utworzenie obiektu cyklicznego

from cycler import cycler
my_cycler = cycler('color', ['k', 'r']) * cycler('linewidth', [1., 1.5, 2.])
actual_cycler = my_cycler()

fig, axes = plt.subplots(2,3)
for ax in axes.flat:
    ax.plot((0,1), (0,1), **next(actual_cycler))

wprowadź opis zdjęcia tutaj

Zauważ, że type(my_cycler)jest, cycler.Cyclerale type(actual_cycler)jest itertools.cycle.

gboffi
źródło
3

Chciałbym zaoferować niewielką poprawę w stosunku do ostatniej odpowiedzi w pętli podanej w poprzednim poście (ten post jest poprawny i nadal powinien zostać zaakceptowany). Domniemane założenie przyjęte podczas etykietowania ostatniego przykładu jest takie, że plt.label(LIST)wstawia numer X LISTlinii z linią odpowiadającą X plotwywołaniu czasu . Wcześniej miałem takie problemy. Zalecanym sposobem budowania legend i dostosowywania ich etykiet na podstawie dokumentacji matplotlibs ( http://matplotlib.org/users/legend_guide.html#adjusting-the-order-of-legend-item ) jest ciepłe poczucie, że etykiety idą wraz z dokładnymi działkami, które według nich wykonują:

...
# Plot several different functions...
labels = []
plotHandles = []
for i in range(1, num_plots + 1):
    x, = plt.plot(some x vector, some y vector) #need the ',' per ** below
    plotHandles.append(x)
    labels.append(some label)
plt.legend(plotHandles, labels, 'upper left',ncol=1)

**: Matplotlib Legends nie działa

Tommy
źródło
3
Tylko fyi: możesz również użyć kwarg „label”, aby wykreślić, a następnie wywołać legendę bez żadnych argumentów.
Joe Kington