127 votes

Comment puis-je définir le ratio d'aspect ?

Je cherche à faire un graphique carré (en utilisant imshow), c'est-à-dire un rapport de 1:1, mais je ne peux pas. Aucun de ces travaux:

import matplotlib.pyplot as plt

ax = fig.add_subplot(111,aspect='equal')
ax = fig.add_subplot(111,aspect=1.0)
ax.set_aspect('equal')
plt.axes().set_aspect('equal')

Il semble que les appels soient simplement ignorés (un problème que j'ai souvent avec matplotlib).

6 votes

Avez-vous essayé ax.axis('equal'), par hasard ? Comme tout le monde l'a dit, ce que vous avez fait devrait fonctionner, mais ax.axis pourrait être une autre option à essayer pour contourner le problème.

88voto

Yann Points 6909

La troisième fois est la bonne. Je suppose qu'il s'agit d'un bug et la réponse de Zhenya suggère que c'est corrigé dans la dernière version. J'ai la version 0.99.1.1 et j'ai créé la solution suivante :

import matplotlib.pyplot as plt
import numpy as np

def forceAspect(ax,aspect=1):
    im = ax.get_images()
    extent =  im[0].get_extent()
    ax.set_aspect(abs((extent[1]-extent[0])/(extent[3]-extent[2]))/aspect)

data = np.random.rand(10,20)

fig = plt.figure()
ax = fig.add_subplot(111)
ax.imshow(data)
ax.set_xlabel('xlabel')
ax.set_aspect(2)
fig.savefig('equal.png')
ax.set_aspect('auto')
fig.savefig('auto.png')
forceAspect(ax,aspect=1)
fig.savefig('force.png')

Ceci est 'force.png': entrer la description de l'image ici

Voici mes tentatives infructueuses, mais espérons-le informatives.

Deuxième réponse :

Ma 'réponse originale' ci-dessous est trop complexe, car elle fait quelque chose de similaire à axes.set_aspect(). Je pense que vous voulez utiliser axes.set_aspect('auto'). Je ne comprends pas pourquoi c'est le cas, mais cela produit un tracé d'image carré pour moi, par exemple ce script :

import matplotlib.pyplot as plt
import numpy as np

data = np.random.rand(10,20)

fig = plt.figure()
ax = fig.add_subplot(111)
ax.imshow(data)
ax.set_aspect('equal')
fig.savefig('equal.png')
ax.set_aspect('auto')
fig.savefig('auto.png')

Produit un tracé d'image avec un rapport de forme 'égal' : entrer la description de l'image ici et un avec un rapport 'auto' : entrer la description de l'image ici

Le code fourni ci-dessous dans la 'réponse originale' fournit un point de départ pour un rapport de forme contrôlé explicitement, mais il semble être ignoré une fois qu'un imshow est appelé.

Réponse originale :

Voici un exemple d'une routine qui ajustera les paramètres du sous-tracé pour que la figure ait le bon rapport de forme :

import matplotlib.pyplot as plt

def adjustFigAspect(fig,aspect=1):
    '''
    Ajuster les paramètres du sous-tracé pour que la figure ait le bon
    rapport de forme.
    '''
    xsize,ysize = fig.get_size_inches()
    minsize = min(xsize,ysize)
    xlim = .4*minsize/xsize
    ylim = .4*minsize/ysize
    if aspect < 1:
        xlim *= aspect
    else:
        ylim /= aspect
    fig.subplots_adjust(left=.5-xlim,
                        right=.5+xlim,
                        bottom=.5-ylim,
                        top=.5+ylim)

fig = plt.figure()
adjustFigAspect(fig,aspect=.5)
ax = fig.add_subplot(111)
ax.plot(range(10),range(10))

fig.savefig('axAspect.png')

Cela produit une figure comme suit : entrer la description de l'image ici

Je peux imaginer si vous avez plusieurs sous-tracés dans la figure, vous voudriez inclure le nombre de sous-tracés y et x en tant que paramètres de mot-clé (par défaut 1 chacun) à la routine fournie. Ensuite, en utilisant ces chiffres et les mots-clés hspace et wspace, vous pouvez faire en sorte que tous les sous-tracés aient le bon rapport de forme.

1 votes

Pour les cas où get_images est une liste vide (comme cela se produirait avec ax.plot([0,1],[0,2]), vous pouvez utiliser get_xlim et get_ylim

0 votes

Il me semble que cela ne fonctionnera pas si vous le faites avec une échelle logarithmique. J'ai ajouté une réponse qui teste cela et le gère. N'hésitez pas à incorporer cela dans votre réponse, puis je supprimerai la mienne.

1 votes

La raison pour laquelle l'aspect semble inégal est que l'aspect égal signifie que la distance visuelle en x sera la même qu'en y. Si l'image est carrée, mais que les valeurs de dx et dy du tracé sont différentes, alors ce n'est pas un ratio d'aspect de 1:1. Le ratio d'aspect sera alors dy/dx dans ce cas.

68voto

Liz Deucker Points 351

Une option simple en utilisant plt.gca() pour obtenir les axes actuels et définir l'aspect

plt.gca().set_aspect('equal')

à la place de votre dernière ligne

0 votes

Meilleure réponse à mon avis. Simple et concis

0 votes

Certainement le meilleur, je mettrais 1.0 comme argument cependant, étant donné que la question est générale.

24voto

Zhenya Points 5885

Quelle est la version de matplotlib que vous utilisez? J'ai récemment dû passer à la version 1.1.0, et avec elle, add_subplot(111,aspect='equal') fonctionne pour moi.

1 votes

Fonctionne bien pour moi dans la version matplotlib 2.0.2. jupyter notebook version 5.0.0. Merci.

6voto

user1021819 Points 372

Après de nombreuses années de succès avec les réponses ci-dessus, j'ai trouvé que cela ne fonctionnait plus - mais j'ai trouvé une solution fonctionnelle pour les sous-graphiques à

https://jdhao.github.io/2017/06/03/change-aspect-ratio-in-mpl

Avec tout le crédit bien sûr à l'auteur ci-dessus (qui pourrait peut-être plutôt poster ici), les lignes pertinentes sont :

ratio = 1.0
xleft, xright = ax.get_xlim()
ybottom, ytop = ax.get_ylim()
ax.set_aspect(abs((xright-xleft)/(ybottom-ytop))*ratio)

Le lien propose également une explication très claire des différents systèmes de coordonnées utilisés par matplotlib.

Merci pour toutes les excellentes réponses reçues - en particulier celle de @Yann qui restera la gagnante.

0 votes

Le lien vers jdhao.github.io/2017/06/03/change-aspect-ratio-in-mpl est très précieux. C'est une exposition encore plus complète : matplotlib.org/tutorials/advanced/transforms_tutorial.html

3voto

joaquin Points 22450

You should try with figaspect. It works for me. From the docs:

Créez une figure avec un rapport hauteur/largeur spécifié. Si arg est un nombre, utilisez ce rapport hauteur/largeur. > Si arg est un tableau, figaspect déterminera la largeur et la hauteur d'une figure qui s'adapterait au tableau en conservant le rapport hauteur/largeur. La largeur et la hauteur de la figure en pouces sont renvoyées. Assurez-vous de créer un axe avec une largeur et une hauteur égales, par exemple

Exemple d'utilisation :

  # créez une figure deux fois plus haute que large
  w, h = figaspect(2.)
  fig = Figure(figsize=(w,h))
  ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])
  ax.imshow(A, **kwargs)

  # créez une figure avec le rapport hauteur/largeur approprié pour un tableau
  A = rand(5,3)
  w, h = figaspect(A)
  fig = Figure(figsize=(w,h))
  ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])
  ax.imshow(A, **kwargs)

Modifier: Je ne suis pas sûr de ce que vous recherchez. Le code ci-dessus modifie le canevas (la taille du graphique). Si vous souhaitez modifier la taille de la fenêtre matplotlib, de la figure, utilisez alors :

In [68]: f = figure(figsize=(5,1))

cela produit une fenêtre de 5x1 (l x h).

0 votes

Merci pour cela - cela a effectivement un effet, en changeant le ratio d'aspect du canevas: Pour être plus précis, j'ai besoin de changer le ratio d'aspect de la figure elle-même, ce que ne fait pas le fait de faire ce qui suit (désolé pour la mise en forme..): fig = plt.figure(figsize=(plt.figaspect(2.0)))

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X