2013-05-22 13 views
11

Sto usando quadmesh per creare un semplice diagramma di proiezione polare. Ecco uno script minima che produce fondamentalmente quello che sto cercando di fare:matplotlib posizionamento barra di colore e dimensione

from __future__ import unicode_literals 
import numpy as np 
import matplotlib.pyplot as plt 

def make_plot(data,fig,subplot): 
    nphi,nt = data.shape 
    phi_coords = np.linspace(0,np.pi*2,nphi+1) - np.pi/2. 
    theta_coords = np.linspace(0,np.radians(35),nt+1) 

    ax = fig.add_subplot(subplot,projection='polar') 
    ax.set_thetagrids((45,90,135,180,225,270,315,360),(9,12,15,18,21,24,3,6)) 
    ax.set_rgrids(np.arange(10,35,10),fmt='%s\u00b0') 

    theta,phi = np.meshgrid(phi_coords,theta_coords) 
    quadmesh = ax.pcolormesh(theta,phi,data) 
    ax.grid(True) 
    fig.colorbar(quadmesh,ax=ax) 
    return fig,ax 


a = np.zeros((360,71)) + np.arange(360)[:,None] 
b = np.random.random((360,71)) 
fig = plt.figure() 
t1 = make_plot(a,fig,121) 
t2 = make_plot(b,fig,122) 
fig.savefig('test.png') 

Lo script precedente crea una trama che assomiglia a questo:

enter image description here

vorrei che la colorbars a:

  1. Non sovrapporre l'etichetta 6.
  2. essere ridimensionato in modo che siano all'incirca della stessa altezza del grafico.

C'è qualche trucco per farlo funzionare correttamente? (Si noti che questo layout non è l'unico che userò, ad esempio potrei usare un layout 1x2 o un layout 4x4 ... Sembra che ci debba essere un modo per ridimensionare la barra dei colori alla stessa altezza del plot associati ...)

risposta

12

si può fare questo con una combinazione dei pad, shrink, e aspect kwargs:

from __future__ import unicode_literals 
import numpy as np 
import matplotlib.pyplot as plt 

def make_plot(data,fig,subplot): 
    nphi,nt = data.shape 
    phi_coords = np.linspace(0,np.pi*2,nphi+1) - np.pi/2. 
    theta_coords = np.linspace(0,np.radians(35),nt+1) 

    ax = fig.add_subplot(subplot,projection='polar') 
    ax.set_thetagrids((45,90,135,180,225,270,315,360),(9,12,15,18,21,24,3,6)) 
    ax.set_rgrids(np.arange(10,35,10),fmt='%s\u00b0') 

    theta,phi = np.meshgrid(phi_coords,theta_coords) 
    quadmesh = ax.pcolormesh(theta,phi,data) 
    ax.grid(True) 
    cb = fig.colorbar(quadmesh,ax=ax, shrink=.5, pad=.2, aspect=10) 
    return fig,ax,cb 


a = np.zeros((360,71)) + np.arange(360)[:,None] 
b = np.random.random((360,71)) 
fig = plt.figure() 
t1 = make_plot(a,fig,121) 
t2 = make_plot(b,fig,122) 

figure.colorbar doc

il valore migliore per questi parametri dipenderà l'aspetto rapporto degli assi.

La dimensione degli assi sembra non essere avvolta nella trama polare, quindi nella disposizione 1x2 c'è molto spazio sopra e sotto la trama che fa parte dell'oggetto degli assi, ma vuota. La dimensione della barra dei colori è esclusa dalla dimensione rettangolare, non dalle dimensioni arrotondate, quindi perché i valori predefiniti non funzionano correttamente. C'è probabilmente un modo per fare il wrapping, ma non so come farlo.

Un metodo alternativo è quello di forzare la vostra figura essere il giusto rapporto di aspetto es:

fig.set_size_inches(10, 4) # for 1x2 
fig.set_size_inches(4, 10) # for 2x1 

che rende il quadrato sub trame, per cui i valori più o meno lavoro.

+0

Questo funziona (più o meno) per il layout 2x1, ma non per un layout 1x2 (quindi la barra dei colori diventa troppo piccola). Sto davvero cercando una soluzione indipendente dal layout. Per quanto riguarda i miei rcparam, non ne sono sicuro. Non ho alcun file rc (per quanto ne so) e 'print matplotlib.rcParams ['bounding_box_tight']' produce un 'KeyError'. – mgilson

+0

@mgilson Ho la chiave dimenticata, vedi modifica. Penso che il problema fondamentale sia che la casella di delimitazione dell'oggetto 'axes' non si restringe attorno al grafico polare e tutte le lunghezze della barra dei colori sono eliminate dal riquadro di delimitazione sovradimensionato. – tacaswell

+0

Ho ancora un 'KeyError' per' savefig.bbox'. Ho anche provato '[v per v in matplotlib.rcParams.values ​​() se isinstance (v, str) e 'tight' in v]' che mi ha dato una lista vuota. Sto usando la versione 1.1.1. – mgilson

15

Questa combinazione (e valori vicini a questi) sembra "magicamente" funzionare per me per mantenere la barra di colore ridimensionata alla trama, indipendentemente dalle dimensioni del display.

plt.colorbar(im,fraction=0.046, pad=0.04) 
+1

Questa è la pazza magia !!! –

+1

Questo ha funzionato perfettamente per me. Utilizzando l'ultima versione di matplotlib (al momento della scrittura). Grazie! – user3125347

0

Il ridimensionamento automatico della barra dei colori è noto per essere difficile. Cercando di applicare il lavoro descritto alla fine di this page non ha funzionato per me con il tuo esempio oi miei tentativi utilizzando un oggetto Axes3D. Dando un'occhiata alla firma della chiamata per lo colorbar, l'argomento della parola chiave ax è "l'oggetto da cui verrà rubato lo spazio per i nuovi assi della barra colorata". Questo spiega perché la barra dei colori si sovrappone al 6. Quindi, dobbiamo mantenere un doppio Axes. Purtroppo, dover mantenere gli assi aggiuntivi significa un sacco di hacking della posizione. Ho messo insieme le seguenti:

#!/usr/bin/env python 
from __future__ import unicode_literals 
import numpy as np 
import matplotlib.pyplot as plt 

fig = plt.figure() 

N, M = 360, 71 
phi_coords = np.linspace(0, np.pi*2, M+1) -np.pi/2 
theta_coords = np.linspace(0, np.radians(35), N+1) 
theta, phi = np.meshgrid(phi_coords, theta_coords) 

# Original method 
a = np.zeros((N,M)) + np.arange(N)[:,None] 
ax1 = fig.add_subplot(1,2,1, projection="polar") 
ax1.set_thetagrids((45,90,135,180,225,270,315,360),(9,12,15,18,21,24,3,6)) 
ax1.set_rgrids(np.arange(10,35,10),fmt='%s\u00b0') 
quadmesh = ax1.pcolormesh(theta, phi, a) 
fig.colorbar(quadmesh,ax=ax1) 

# Use ``add_axes`` to make a ``cax`` 
b = np.random.random((N,M)) 
ax2 = fig.add_subplot(1,2,2, projection="polar") 
ax2.set_thetagrids((45,90,135,180,225,270,315,360),(9,12,15,18,21,24,3,6)) 
ax2.set_rgrids(np.arange(10,35,10),fmt='%s\u00b0') 
quadmesh = ax2.pcolormesh(theta, phi, b) 
# <hack> 
# Hack to force the drawing of the image. 
print(ax2.get_position()) 
import tempfile 
with tempfile.SpooledTemporaryFile() as fid: 
    fig.savefig(fid, format="png") 

# </hack> 
# Now the axes has been scaled to the final size. 
bbox = ax2.get_position() 
print(bbox) 
cax = fig.add_axes(
     [bbox.xmax*1.03, bbox.ymin, bbox.width*0.08, bbox.height] 
    ) 
fig.colorbar(quadmesh,cax=cax) 

fig.savefig('test.png') 

L'immagine a sinistra è la stessa come l'originale, ma l'immagine destra ha la barra dei colori offset dal diagramma polare e l'altezza della barra corrisponde al diagramma polare .Come puoi vedere, ho dovuto forzare la figura per disegnare al fine di ottenere la dimensione dell'asse giusta per la trama della mano sinistra. Se non si forza il ridisegno, la dimensione della barra dei colori si basa sulla dimensione degli assi originali e si ottengono gli stessi assi delle dimensioni della sinistra. A questo punto, non ho trovato un modo per dire allo Axes che la barra dei colori segua automaticamente lo Axes principale per le variazioni di dimensione.

Problemi correlati