2013-08-12 27 views
11

Czy możliwe byłoby posiadanie poziomów paska koloru w skali logu, jak na poniższym obrazku?wykres konturu matplotlib: proporcjonalne poziomy paska kolorów w skali logarytmicznej

enter image description here

Oto przykładowy kod gdzie może być realizowany:

import matplotlib.pyplot as plt 
import numpy as np 
from matplotlib.colors import LogNorm 
delta = 0.025 

x = y = np.arange(0, 3.01, delta) 
X, Y = np.meshgrid(x, y) 
Z1 = plt.mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0) 
Z2 = plt.mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1) 
Z = 1e6 * (Z1* Z2) 

fig=plt.figure() 
ax1 = fig.add_subplot(111) 
lvls = np.logspace(0,4,20) 
CF = ax1.contourf(X,Y,Z, 
     norm = LogNorm(), 
     levels = lvls 
     ) 
CS = ax1.contour(X,Y,Z, 
     norm = LogNorm(), 
     colors = 'k', 
     levels = lvls 
     ) 
cbar = plt.colorbar(CF, ticks=lvls, format='%.4f') 
plt.show() 

enter image description here

Używam Pythona 2.7.3 z matplotlib 1.1.1 na Windows 7.

+0

Twój pasek koloru _ już ma logarytmiczną skalę. – hooy

+2

@nordev - Uważam, że OP pyta, jak ustawić lokalizator ticków i formatter na pasku kolorów, aby wyświetlać etykiety w regularnych odstępach czasu. –

+0

@JoeKington Ah, wydawało mi się pamiętać, że OP w jego [pierwotne pytanie] (http://stackoverflow.com/revisions/17951672/1) chciał, aby znaczniki zostały umieszczone na wartości podane w tablicy 'lvls' z odstępy logarytmiczne, ale może po prostu błędnie rozumiem, co miał na myśli. Dziękuję za wskazanie. – hooy

Odpowiedz

13

Proponuję wygenerować pseudobolorbar w następujący sposób (patrz komentarze do objaśnień):

import matplotlib.pyplot as plt 
import numpy as np 
from matplotlib.colors import LogNorm 
import matplotlib.gridspec as gridspec 

delta = 0.025 

x = y = np.arange(0, 3.01, delta) 
X, Y = np.meshgrid(x, y) 
Z1 = plt.mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0) 
Z2 = plt.mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1) 
Z = 1e6 * (Z1 * Z2) 

fig=plt.figure() 

# 
# define 2 subplots, using gridspec to control the 
# width ratios: 
# 
# note: you have to import matplotlib.gridspec for this 
# 
gs = gridspec.GridSpec(1, 2,width_ratios=[15,1]) 

# the 1st subplot 
ax1 = plt.subplot(gs[0]) 

lvls = np.logspace(0,4,20) 

CF = ax1.contourf(X,Y,Z, 
        norm = LogNorm(), 
        levels = lvls 
       ) 
CS = ax1.contour(X,Y,Z, 
       norm = LogNorm(), 
       colors = 'k', 
       levels = lvls 
       ) 

# 
# the pseudo-colorbar 
# 

# the 2nd subplot 
ax2 = plt.subplot(gs[1])   

# 
# new levels! 
# 
# np.logspace gives you logarithmically spaced levels - 
# this, however, is not what you want in your colorbar 
# 
# you want equally spaced labels for each exponential group: 
# 
levls = np.linspace(1,10,10) 
levls = np.concatenate((levls[:-1],np.linspace(10,100,10))) 
levls = np.concatenate((levls[:-1],np.linspace(100,1000,10))) 
levls = np.concatenate((levls[:-1],np.linspace(1000,10000,10))) 

# 
# simple x,y setup for a contourf plot to serve as colorbar 
# 
XC = [np.zeros(len(levls)), np.ones(len(levls))] 
YC = [levls, levls] 
CM = ax2.contourf(XC,YC,YC, levels=levls, norm = LogNorm()) 
# log y-scale 
ax2.set_yscale('log') 
# y-labels on the right 
ax2.yaxis.tick_right() 
# no x-ticks 
ax2.set_xticks([]) 

plt.show() 

To daje działkę takiego:

pseudo-colorbar

EDIT

Lub użyć czegoś podobnego nowych poziomów i opcji spacing='proportional' podczas wywoływania colorbar:

  1. re umieścić ten wiersz:

    lvls = np.logspace(0,4,20) 
    

    z nich:

    lvls = np.linspace(1,10,5) 
    lvls = np.concatenate((lvls[:-1],np.linspace(10,100,5))) 
    lvls = np.concatenate((lvls[:-1],np.linspace(100,1000,5))) 
    lvls = np.concatenate((lvls[:-1],np.linspace(1000,10000,5))) 
    
  2. zastąpić ten wiersz:

    cbar = plt.colorbar(CF, ticks=lvls, format='%.4f') 
    

    z tym:

    cbar = plt.colorbar(CF, ticks=lvls, format='%.2f', spacing='proportional') 
    

I będzie w końcu z tej działki:

real-colorbar

(format została tylko zmieniona, ponieważ nowe kleszcze nie wymagają 4 dziesiętne)

EDIT 2
jeśli chciałem automatycznie generować poziomy takie jak te, których używałem, możesz wziąć pod uwagę ten fragment kodu:

levels = [] 
LAST_EXP = 4 
N_LEVELS = 5 
for E in range(0,LAST_EXP): 
    levels = np.concatenate((levels[:-1],np.linspace(10**E,10**(E+1),N_LEVELS)))