2017-10-21 46 views
0

Mon dans mon "monde réel" problème je veux recalculer les valeurs xy écrites dans l'étiquette de graduation de ma figure après que je l'ai zoomé dans un tel Ainsi, l'origine est toujours à (0,0) et évidemment les distances relatives des valeurs sur les axes x et y restent les mêmes. Mon problème a été résolu dans ce fil: Initial solutionCréation d'une barre de couleurs décale deux objets axe précédemment alignés les uns par rapport aux autres - Matplotlib

La solution comprend la création d'un axe invisible qui maintient l'intrigue et un axe visible qui obtient différents lables tiques après un zoom.

Dans mon cas, je veux superposer plusieurs parcelles de compteurs et coutourf. Pour une seule de ces parcelles, je veux ajouter une barre de couleur à la figure! Mais lorsque je crée la barre de couleurs dans mon script, les objets à deux axes que j'ai créés sont décalés l'un par rapport à l'autre. Sans la barre de couleur, ils sont parfaitement alignés!

Voici un MWE qui recrée à peu près le comportement:

import matplotlib.pyplot as plt 
import numpy as np 
from matplotlib import mlab, cm 

# Default delta is large because that makes it fast, and it illustrates 
# the correct registration between image and contours. 
delta = 0.5 

extent = (-3, 4, -4, 3) 

x = np.arange(-3.0, 4.001, delta) 
y = np.arange(-4.0, 3.001, delta) 
X, Y = np.meshgrid(x, y) 
Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0) 
Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1) 
Z = (Z1 - Z2) * 10 

levels = np.arange(-2.0, 1.601, 0.4) # Boost the upper limit to avoid truncation errors. 

norm = cm.colors.Normalize(vmax=abs(Z).max(), vmin=-abs(Z).max()) 
cmap = cm.PRGn 




# ax is empty 
fig, ax = plt.subplots() 
ax.set_navigate(False) 
# ax2 will hold the plot, but has invisible labels 
ax2 = fig.add_subplot(111,zorder=2) 

ax2.contourf(X, Y, Z, levels, 
       cmap=cm.get_cmap(cmap, len(levels) - 1), 
       norm=norm, 
       ) 
ax2.axis("off") 

ax.set_xlim(ax2.get_xlim()) 
ax.set_ylim(ax2.get_ylim()) 

# 
# Declare and register callbacks 
def on_lims_change(axes): 
    # change limits of ax, when ax2 limits are changed. 
    a=ax2.get_xlim() 
    ax.set_xlim(0, a[1]-a[0]) 
    a=ax2.get_ylim() 
    ax.set_ylim(0, a[1]-a[0]) 



sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) #Do not show unnecessary parts of the colormap 
sm._A = [] 
cb = plt.colorbar(sm,extend="both", label="units") 
cb.ax.tick_params(labelsize=10) 


ax2.callbacks.connect('xlim_changed', on_lims_change) 
ax2.callbacks.connect('ylim_changed', on_lims_change) 
ax.axis('scaled') 
plt.axis('scaled') 
# Show 
plt.show() 

Maintenant, le contourplot semble être déplacé realtive à l'axe visible. J'ai trouvé quelques conseils en ligne qui suggèrent que la « boîte à colorbar mange automatiquement l'espace des axes auxquels il est attaché » Link1 Link2

Mais je ne sais pas vraiment ce que je dois faire pour changer ce comportement Je ne comprends pas si mon problème est lié.

S'il vous plaît noter que la partie:

ax.axis('scaled') 
plt.axis('scaled') 

est nécessaire que je dois maintenir le ratio d'aspect exactement comme il est dans l'ensemble de données!

Merci d'avance!

Répondre

1

Vous pouvez changer la position de ax (les axes vides avec les étiquettes) à la position de ax2 (les axes montrant les données) après avoir ajouté le colorbar via

ax.set_position(ax2.get_position()) 

Vous pouvez également créer le colorbar par " endurcir » l'espace des deux axes,

cb = fig.colorbar(sm,ax=[ax,ax2], extend="both", label="units") 

les deux solutions se trouvent dans les réponses à this linked question.


Voici quelques améliorations supplémentaires en dehors de la portée réelle de la question:

ax.axis('scaled') 
ax2.axis('scaled') 

De plus, mettre la ax au-dessus si le ax2, de sorte que le tracé de contourf ne se chevauchent pas les épines axes.

# put `ax` on top, to let the contours not overlap the shown axes 
ax.set_zorder(2)  
ax.patch.set_visible(False) 
# ax2 will hold the plot, but has invisible labels 
ax2 = fig.add_subplot(111,zorder=1) 

Code complet:

import matplotlib.pyplot as plt 
import numpy as np 
from matplotlib import mlab, cm 

delta = 0.5 
extent = (-3, 4, -4, 3) 
x = np.arange(-3.0, 4.001, delta) 
y = np.arange(-4.0, 3.001, delta) 
X, Y = np.meshgrid(x, y) 
Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0) 
Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1) 
Z = (Z1 - Z2) * 10 

levels = np.arange(-2.0, 1.601, 0.4) 

norm = cm.colors.Normalize(vmax=abs(Z).max(), vmin=-abs(Z).max()) 
cmap = cm.PRGn 

# ax is empty 
fig, ax = plt.subplots() 
ax.set_navigate(False) 
# put `ax` on top, to let the contours not overlap the shown axes 
ax.set_zorder(2)  
ax.patch.set_visible(False) 
# ax2 will hold the plot, but has invisible labels 
ax2 = fig.add_subplot(111,zorder=1) 

ax2.contourf(X, Y, Z, levels, 
       cmap=cm.get_cmap(cmap, len(levels) - 1), 
       norm=norm, 
       ) 
ax2.axis("off") 

ax.set_xlim(ax2.get_xlim()) 
ax.set_ylim(ax2.get_ylim()) 

# 
# Declare and register callbacks 
def on_lims_change(axes): 
    # change limits of ax, when ax2 limits are changed. 
    a=ax2.get_xlim() 
    ax.set_xlim(0, a[1]-a[0]) 
    a=ax2.get_ylim() 
    ax.set_ylim(0, a[1]-a[0]) 


sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) 
sm._A = [] 
cb = fig.colorbar(sm,ax=[ax,ax2], extend="both", label="units") 
cb.ax.tick_params(labelsize=10) 

ax2.callbacks.connect('xlim_changed', on_lims_change) 
ax2.callbacks.connect('ylim_changed', on_lims_change) 
ax.axis('scaled') 
ax2.axis('scaled') 
#ax.set_position(ax2.get_position()) 
# Show 
plt.show() 

enter image description here

+0

j'ai essayé de mettre en œuvre la solution dans le fil sans succès qui met en évidence mon manque de compréhension. Le problème auquel je suis confronté est que, si je veux ajouter 'matplotlib.patches' comme ceci 'circle = Circle ((- 3, 2), 0.1, color = 'r') ax2.add_patch (cercle)'. Lorsque le patch est ajouté au bord du tracé, la plage X-Y affichée change pour montrer le cercle complet et les coordonnées décalées. Est-ce lié à l'appel de 'ax.axis ('scaled') ax2.axis ('scaled')' .... J'apprécierais un pourboire était de regarder comme je ne trouve rien quand je le cherche. Merci pour votre solution! C'est vraiment apprécié! – NorrinRadd

+0

Vous devez ajouter le cercle (ou n'importe quoi) * avant * d'appeler 'ax.set_xlim (ax2.get_xlim())'. – ImportanceOfBeingErnest

+0

Je sais que cette communauté est un peu limitée sur les expressions exagérées de ses remerciements ... mais honnêtement, je voudrais vous acheter une bière ou quelque chose ... Cela a résolu un problème très immédiat pour moi! Je vous remercie! – NorrinRadd