2013-11-22 13 views
13

Veri kümesi için doldurulmuş bir kontur oluşturmaya çalışıyorum. Oldukça basit olmalıdır:Shifted colorbar matplotlib

plt.contourf(x, y, z, label = 'blah', cm = matplotlib.cm.RdBu) 

benim veri kümesi 0 etrafında simetrik olmayan, ancak ben ne yapacağım? Diyelim ki maviden (negatif değerler) 0'a (beyaz), kırmızıya (pozitif değerler) gitmek istiyorum. Veri kümem-8'den 3'e doğru giderse, o zaman renk çubuğunun beyaz kısmı 0'da olmalıdır, aslında biraz negatiftir. Renk çubuğunu değiştirmenin bir yolu var mı?

cevap

29

İlk olarak, bunu yapmanın birden fazla yolu var.

  1. contourf için colors kwarg kullanın ve renkleri el
  2. Kullanım özel Normalize sınıf belirtmek ve norm kwarg olarak bir örneğini geçmektedir.
  3. matplotlib.colors.from_levels_and_colors ile oluşturulmuş ayrı bir renk haritası kullanın.

En basit yol, colors=sequence_of_colors ile belirli renklerden geçirmektir. Ancak, kontur sayısını manuel olarak ayarlamadıysanız, bu rahatsız edici olabilir.

En esnek yol ikinci seçenek: özel bir normalleştirme belirtmek için norm kwarg kullanın. İstediğiniz şey için, Normalize alt sınıfına ihtiyacınız var, ancak bunun yapılması çok zor değil. Sürekli bir renk haritası kullanmanıza izin veren tek seçenek budur.

İkinci veya üçüncü seçenekleri kullanmanın nedeni, bir colormap kullanan her tür matplotlib çiziminde çalışacaklarıdır (örneğin, imshow, scatter, vb.). Üçüncü seçenek, belirli renklerden ayrı bir renk haritası ve normalleştirme nesnesi oluşturur. Temel olarak ilk seçenekle aynıdır, ancak a) kontur parsellerinden başka parsel tipleri ile çalışacaktır ve b) kontur sayısını elle belirtmek zorunda kalmamalıdır. İkinci seçenek bir örnek olarak

(rastgele veriler için contourf daha mantıklı çünkü burada imshow kullanacağız, ancak contourf interpolation seçenekten başka özdeş kullanım olurdu.):

import numpy as np 
import matplotlib.pyplot as plt 
from matplotlib.colors import Normalize 

class MidpointNormalize(Normalize): 
    def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False): 
     self.midpoint = midpoint 
     Normalize.__init__(self, vmin, vmax, clip) 

    def __call__(self, value, clip=None): 
     # I'm ignoring masked values and all kinds of edge cases to make a 
     # simple example... 
     x, y = [self.vmin, self.midpoint, self.vmax], [0, 0.5, 1] 
     return np.ma.masked_array(np.interp(value, x, y)) 

data = np.random.random((10,10)) 
data = 10 * (data - 0.8) 

fig, ax = plt.subplots() 
norm = MidpointNormalize(midpoint=0) 
im = ax.imshow(data, norm=norm, cmap=plt.cm.seismic, interpolation='none') 
fig.colorbar(im) 
plt.show() 

import numpy as np 
import matplotlib.pyplot as plt 
from matplotlib.colors import from_levels_and_colors 

data = np.random.random((10,10)) 
data = 10 * (data - 0.8) 

num_levels = 20 
vmin, vmax = data.min(), data.max() 
midpoint = 0 
levels = np.linspace(vmin, vmax, num_levels) 
midp = np.mean(np.c_[levels[:-1], levels[1:]], axis=1) 
vals = np.interp(midp, [vmin, midpoint, vmax], [0, 0.5, 1]) 
colors = plt.cm.seismic(vals) 
cmap, norm = from_levels_and_colors(levels, colors) 

fig, ax = plt.subplots() 
im = ax.imshow(data, cmap=cmap, norm=norm, interpolation='none') 
fig.colorbar(im) 
plt.show() 
: üçüncü seçenek bir örnek olarak

enter image description here (bildirimi bu yerine, sürekli bir renk haritası ayrı bir renk haritası verir)

enter image description here

+0

Harika, bu sadece aradığım şeydi, teşekkürler! – pgierz

+2

Matplotlib – Moritz

+0

@Joe Kington'a eklenmeli, bu gerçekten harikaydı! Açık kaynaklı bir proje için sınıf tanımınızı kopyalıyorum ve isminizi yazar olarak yazdım. Umarım onunla iyi olur. –