Matplotlib renk döngüsü durumunu alın


90

Matplotlib renk döngüsünün mevcut durumunu sorgulamak mümkün mü? Başka bir deyişle get_cycle_stateaşağıdaki şekilde davranacak bir işlev var mı?

>>> plot(x1, y1)
>>> plot(x2, y2)
>>> state = get_cycle_state()
>>> print state
2

Durumun bir çizimde kullanılacak bir sonraki rengin indeksi olmasını beklediğim yer. Alternatif olarak, bir sonraki rengi (yukarıdaki örnekte varsayılan döngü için "r") döndürdüyse, bu da iyi olur.


Bu, mevcut durumu değiştirmeden bile yapılabilir, aşağıdaki yanıta bakın
sancho.s ReinstateMonicaCellio

Yanıtlar:


110

Renk döngüsü yineleyicisine erişim

Temel yineleyiciye erişmek için "kullanıcıya dönük" ("genel" olarak da bilinen) bir yöntem yoktur, ancak buna "özel" (geleneksel) yöntemlerle erişebilirsiniz. Ancak, bir durumunu iteratordeğiştirmeden elde edemezsiniz .

Renk döngüsünü ayarlama

Hızlı kenara: Renk / özellik döngüsünü çeşitli şekillerde ayarlayabilirsiniz (örn ax.set_color_cycle. <1.5 veya ax.set_prop_cycler> = 1.5 sürümlerinde ). 1.5 veya üstü sürüm için buradaki örneğe veya buradan önceki stile bir göz atın .

Temel yineleyiciye erişim

Bununla birlikte, yinelenebilir öğeye erişmek için halka açık bir yöntem olmasa da, yardımcı sınıf örneği axaracılığıyla belirli bir eksen nesnesi ( ) için ona erişebilirsiniz _get_lines. ax._get_lineskafa karıştırıcı bir şekilde adlandırılmış bir dokunuş, ancak plotkomutun plotçağrılabilecek tüm garip ve çeşitli yolları işlemesine izin veren perde arkası mekanizması . Diğer şeylerin yanı sıra, hangi renklerin otomatik olarak atanacağını takip eden şeydir. Benzer şekilde, ax._get_patches_for_fillvarsayılan dolgu renkleri ve yama özellikleri arasında geçişi kontrol etmek için var .

Her halükarda, yinelenebilir renk döngüsü ax._get_lines.color_cycleçizgiler ve ax._get_patches_for_fill.color_cycleyamalar içindir. Matplotlib> = 1.5'te, bu kitaplığı kullanmak içincycler değiştirildi ve yinelenebilir prop_cycleryerine çağrılır color_cycleve dictyalnızca bir renk yerine a of özellikleri verir .

Sonuç olarak, şöyle bir şey yaparsınız:

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
color_cycle = ax._get_lines.color_cycle
# or ax._get_lines.prop_cycler on version >= 1.5
# Note that prop_cycler cycles over dicts, so you'll want next(cycle)['color']

Bir durumunu göremezsin iterator

Ancak bu nesne "çıplak" tır iterator. Biz kolayca sonraki öğeyi (örneğin alabilirsiniz next_color = next(color_cycle), ancak sonraki renk o araçlar bundan sonra çizilen olacak budur. Tasarım gereği, bunu değiştirmeden bir yineleyici mevcut durumunu almak için bir yolu yoktur.

İçinde v1.5veya daha fazlası, cyclermevcut durumunu çıkarabildiğimiz için kullanılan nesneyi elde etmek güzel olurdu . Ancak, cyclernesnenin kendisine hiçbir yerden erişilemez (genel veya özel olarak). Bunun yerine, yalnızca nesneden itertools.cycleoluşturulan örneğe cyclererişilebilir. Her iki durumda da, renk / özellik döngüleyicisinin temel durumuna ulaşmanın bir yolu yoktur.

Bunun yerine önceden çizilen öğenin rengini eşleştirin

Sizin durumunuzda, az önce çizilen bir şeyin rengiyle eşleştirmek istiyormuşsunuz gibi geliyor. Rengin / özelliğin ne olacağını belirlemeye çalışmak yerine, çizilen öğenin özelliklerine göre yeni öğenizin rengini / vb. Ayarlayın.

Örneğin, açıkladığınız durumda, şöyle bir şey yapacağım:

import matplotlib.pyplot as plt
import numpy as np

def custom_plot(x, y, **kwargs):
    ax = kwargs.pop('ax', plt.gca())
    base_line, = ax.plot(x, y, **kwargs)
    ax.fill_between(x, 0.9*y, 1.1*y, facecolor=base_line.get_color(), alpha=0.5)

x = np.linspace(0, 1, 10)
custom_plot(x, x)
custom_plot(x, 2*x)
custom_plot(x, -x, color='yellow', lw=3)

plt.show()

görüntü açıklamasını buraya girin

Tek yol bu değil, ama bu durumda çizilen çizginin rengini önceden elde etmeye çalışmaktan daha temiz.


Çalışma alanım için genel çizim görevlerini otomatikleştirmek için bazı üst düzey işlevler yazıyorum. Genellikle bunlar birden fazla matplotlib nesnesinin çizilmesini gerektirir ve birkaç nesnenin renk döngüsünde bir rengi paylaşmasını isterim, bu nedenle tembel hissediyorsam her zaman bir renk argümanı sağlamak zorunda kalmam.
mwaskom

12
Sadece belirli bir nesnenin rengiyle eşleştirmek istiyorsanız, her zaman rengini yakalayabilirsiniz. örneğin line, = ax.plot(x, y)ve daha sonra line.get_color()önceden çizilen çizginin rengini elde etmek için kullanın .
Joe Kington

3
ax._get_lines.color_cycle1.5'te artık yok gibi görünüyor ?
endolith

6
Bence (yakın) eşdeğer, yanıtta önerilenin eşdeğerini yapmak için takip edilen ax._get_lines.prop_cyclergibi bir yapıya sahip olabileceğiniz bir yinelenebilir , inanıyorum. Sadece renklerin tekrarlanabilir olup olamayacağından emin değilim, daha fazlasını keşfetmem gerekiyor. if 'color' in ax._get_lines._prop_keys:next(ax._get_lines.prop_cycler)['color']color_cycle
J Richard Snape

1
@endolith Tabii (ve teşekkürler) - ama Joe'nun zaten çok iyi ve kabul edilmiş cevabında oturmanın daha iyi olacağını hissettim. Pazartesiye kadar teslim edemezse - Korkunç "yorumlara cevap" yerine oraya uygun bir cevap vereceğim
J Richard Snape

26

Aşağıda, alt çizgilerle birlikte gelen yöntemlere dayanmadığı için geleceğe dönük olması umulan 1.5 sürümünde işe yarayan bir yol var:

colors = plt.rcParams["axes.prop_cycle"].by_key()["color"]

Bu size mevcut stil için tanımlanan renklerin bir listesini verecektir.


1
2.0.2'de çalışır.
KevinG

16

Not: Matplotlib'in son sürümlerinde (> = 1.5) _get_linesdeğişmiştir. Artık kullanmaya gerek next(ax._get_lines.prop_cycler)['color']Python 2 veya 3 (veya içinde ax._get_lines.prop_cycler.next()['color']yer Python 2 renk döngüsünden sonraki renk elde etmek için).

Mümkün olan her yerde, @ joe-kington'ın yanıtının alt kısmında gösterilen daha doğrudan yaklaşımı kullanın. Gibi _get_linesdeğil gelecekte bir değil geriye uyumlu şekilde tekrar değişebileceğini API bakan.


Renk döngüleyicinin bir sonraki öğesini sorgulamanın döngüleyicinin durumunu değiştirmesini nasıl önleyebilirsiniz?
kazemakase

6

Elbette, bu yapacak.

#rainbow

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0,2*np.pi)
ax= plt.subplot(1,1,1)
ax.plot(np.sin(x))
ax.plot(np.cos(x))

rainbow = ax._get_lines.color_cycle
print rainbow
for i, color in enumerate(rainbow):
    if i<10:
        print color,

Verir:

<itertools.cycle object at 0x034CB288>
r c m y k b g r c m

İşte matplotlib'in itertools kullandığı itertools işlevi.

Düzenleme: Yorumunuz için teşekkürler, bir yineleyiciyi kopyalamak mümkün değil gibi görünüyor. Bir fikir, tam bir döngüden kurtulmak ve hangi değeri kullandığınızı takip etmek olabilir, buna geri döneyim.

Edit2: Pekala, bu size bir sonraki rengi verecek ve sanki bir sonraki çağrılmamış gibi davranan yeni bir yineleyici yapacak. Bu renklendirme sırasını korumaz, sadece bir sonraki renk değerini size bırakıyorum.

Bu, aşağıdaki çıktıyı verir, grafikteki dikliğin indekse karşılık geldiğine dikkat edin, örneğin ilk g en alttaki grafiktir vb.

#rainbow

import matplotlib.pyplot as plt
import numpy as np
import collections
import itertools

x = np.linspace(0,2*np.pi)
ax= plt.subplot(1,1,1)


def create_rainbow():
    rainbow = [ax._get_lines.color_cycle.next()]
    while True:
        nextval = ax._get_lines.color_cycle.next()
        if nextval not in rainbow:
            rainbow.append(nextval)
        else:
            return rainbow

def next_color(axis_handle=ax):
    rainbow = create_rainbow()
    double_rainbow = collections.deque(rainbow)
    nextval = ax._get_lines.color_cycle.next()
    double_rainbow.rotate(-1)
    return nextval, itertools.cycle(double_rainbow)


for i in range(1,10):
    nextval, ax._get_lines.color_cycle = next_color(ax)
    print "Next color is: ", nextval
    ax.plot(i*(x))


plt.savefig("SO_rotate_color.png")
plt.show()

Konsol

Next color is:  g
Next color is:  c
Next color is:  y
Next color is:  b
Next color is:  r
Next color is:  m
Next color is:  k
Next color is:  g
Next color is:  c

Rengi döndür


Teşekkürler! Sadece açıklığa kavuşturmak için, bu bir kopya döndürüyor gibi görünmüyor, daha çok gerçek döngüye bir referans veriyor. Yani, rainbow.next () 'i çağırmak aslında bir sonraki grafiğin neye benzeyeceğini de değiştirecek.
mwaskom

5

@Andi'nin yukarıda söylediklerine eklemek istiyorum. Yana color_cyclematplotlib 1.5 önerilmiyor, sen kullanımına sahip prop_cycler, ancak, Andi'nin çözeltisi ( ax._get_lines.prop_cycler.next()['color']) benim için bu hatayı döndürdü:

AttributeError: 'itertools.cycle' nesnesinin 'next' niteliği yok

Benim için çalışan kod şuydu: next(ax._get_lines.prop_cycler) yarayan aslında @ joe-kington'ın orijinal yanıtından çok uzak değil.

Şahsen, renk döngüleyiciyi sıfırlayan bir twinx () ekseni yaparken bu problemle karşılaştım. Renkleri doğru bir şekilde değiştirmenin bir yolunu kullanıyordum çünkü style.use('ggplot'). Bunu yapmanın daha kolay / daha iyi bir yolu olabilir, bu yüzden beni düzeltmekten çekinmeyin.


Lütfen gönderinizi bir tartışma materyali olarak değil, bir cevap olarak biçimlendirin (aksi halde bir yorumdur), asıl amacınız next(ax._get_lines.prop_cycler)olası bir alternatiftir.
UmNyobe

@Carson Aramanın next(ax._get_lines.prop_cycler)renk döngüleyicinin durumunu gerçekten değiştirmesini nasıl engellersiniz ?
kazemakase

Aslında yapmaya çalıştığım şey bu - prop_cycler. Bu sorunun kabul edilen cevabını okursanız, durumunu prop_cyclerdeğiştirmeden durumuna erişmenin bir yolu olmadığını göreceksiniz çünkü bu bir yinelenebilir.
Carson

İşaret ettiğiniz hata bir Python 2 / Python 3 farkıdır. Buna işaret ettiğiniz için teşekkürler, cevabımı buna göre düzenledim.
Andi

1

Matplotlib kullandığından itertools.cycle, aslında tüm renk döngüsüne bakabilir ve ardından yineleyiciyi önceki durumuna geri yükleyebiliriz:

def list_from_cycle(cycle):
    first = next(cycle)
    result = [first]
    for current in cycle:
        if current == first:
            break
        result.append(current)

    # Reset iterator state:
    for current in cycle:
        if current == result[-1]:
            break
    return result

Bu, yineleyicinin durumunu değiştirmeden listeyi döndürmelidir.

Matplotlib> = 1.5 ile kullanın:

>>> list_from_cycle(ax._get_lines.prop_cycler)
[{'color': 'r'}, {'color': 'g'}, {'color': 'b'}]

veya matplotlib <1.5 ile:

>>> list_from_cycle(ax._get_lines.color_cycle)
['r', 'g', 'b']

0

Döngüleyici aracılığıyla tüm döngüyü yapmadan bulabileceğim en basit yol ax1.lines[-1].get_color().


-1

Matplotlib sürüm 2.2.3'te özellik get_next_color()üzerinde bir yöntem vardır _get_lines:

import from matplotlib import pyplot as plt
fig, ax = plt.subplots()
next_color = ax._get_lines.get_next_color()

get_next_color() bir html renk dizesi döndürür ve renk döngüsü yineleyicisini ilerletir.


-1

Renk (ve eksiksiz stil) döngüsüne nasıl erişilir?

Mevcut durum, içinde saklanır ax._get_lines.prop_cycler. Bir jenerik için itertools.cycleve özellikle de ax._get_lines.prop_cycler(aşağıya bakın) için "temel listeyi" ortaya çıkarmak için yerleşik yöntemler yoktur .

Ben gönderdiniz burada bir ilgili bilgi almak için birkaç fonksiyonlar itertools.cycle. Biri o zaman kullanabilir

style_cycle = ax._get_lines.prop_cycler
curr_style = get_cycle_state(style_cycle)  # <-- my (non-builtin) function
curr_color = curr_style['color']

döngünün durumunu değiştirmeden mevcut rengi elde etmek için .


TL; DR

Renk (ve tam stil) döngüsü nerede saklanır?

Stil döngüsü, biri varsayılan ve diğeri de geçerli eksenler için olmak üzere iki farklı yerde saklanır ( import matplotlib.pyplot as pltve axbir eksen işleyicisi olduğu varsayılırsa ):

default_prop_cycler = plt.rcParams['axes.prop_cycle']
current_prop_cycle = ax._get_lines.prop_cycler

Bunların farklı sınıfları olduğunu unutmayın. Varsayılan, bir "temel döngü ayarı" dır ve herhangi bir eksen için herhangi bir mevcut durumu bilmezken, akım izlenecek döngüyü ve mevcut durumunu bilir:

print('type(default_prop_cycler) =', type(default_prop_cycler))
print('type(current_prop_cycle) =', type(current_prop_cycle))

[]: type(default_prop_cycler) = <class 'cycler.Cycler'>
[]: type(current_prop_cycle) = <class 'itertools.cycle'>

Varsayılan döngü, döngü için birkaç tuşa (özelliğe) sahip olabilir ve biri yalnızca renkleri alabilir:

print('default_prop_cycler.keys =', default_prop_cycler.keys)
default_prop_cycler2 = plt.rcParams['axes.prop_cycle'].by_key()
print(default_prop_cycler2)
print('colors =', default_prop_cycler2['color'])

[]: default_prop_cycler.keys = {'color', 'linestyle'}
[]: {'color': ['r', 'g', 'b', 'y'], 'linestyle': ['-', '--', ':', '-.']}
[]: colors = ['r', 'g', 'b', 'y']

Hatta değişebilir cyclerbelirli bir için kullanmak axesolduğunu tanımlayan sonra, custom_prop_cyclerbirlikte,

ax.set_prop_cycle(custom_prop_cycler)

Ancak, bir jenerik için itertools.cycleve özellikle için "temel listeyi" ortaya çıkarmak için yerleşik yöntemler yoktur ax._get_lines.prop_cycler.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.