104 votes

Matplotlib savefig() tracés différents de show()

Lorsque j'utilise show() pour tracer les graphiques dans X, les graphiques ont l'air très bien. Cependant, lorsque je commence à utiliser savefig() pour générer un grand nombre de graphiques, les graphiques générés par savefig() ont une police, des lignes, des polygones qui semblent tous plus petits que le graphique généré par show(). Mon environnement est Ubuntu et le backend pour show() est Qt4Agg. Comment puis-je rendre le graphique généré par show() et celui généré par savefig() cohérents?

112voto

Joe Kington Points 68089

savefig spécifie le DPI de la figure enregistrée (Le défaut est 100 s'il n'est pas spécifié dans votre .matplotlibrc, jetez un œil à l'argument dpi de savefig). Il ne le hérite pas du DPI de la figure originale.

Le DPI affecte la taille relative du texte et la largeur du trait sur les lignes, etc. Si vous voulez que les choses aient l'air identiques, passez fig.dpi à fig.savefig.

Par exemple

import matplotlib.pyplot as plt

fig = plt.figure()
plt.plot(range(10))
fig.savefig('temp.png', dpi=fig.dpi)

45voto

brium-brium Points 112

Ancienne question, mais apparemment Google l'aime donc j'ai pensé mettre une réponse ici après quelques recherches sur ce problème.

Si vous créez une figure à partir de zéro, vous pouvez lui donner une option de taille lors de sa création :

import matplotlib.pyplot as plt

fig = plt.figure(figsize=(3, 6))

plt.plot(range(10)) #exemple de tracé
plt.show() #pour le contrôle

fig.savefig('temp.png', dpi=fig.dpi)

figsize(largeur, hauteur) ajuste la dimension absolue de votre tracé et aide à s'assurer que les deux tracés ont une apparence similaire.

Comme indiqué dans une autre réponse, l'option dpi affecte la taille relative du texte et la largeur des traits sur les lignes, etc. En utilisant l'option dpi=fig.dpi, vous vous assurez que la taille relative de ceux-ci est la même à la fois pour show() et savefig().

Alternativement, la taille de la figure peut être modifiée après sa création avec :

fig.set_size_inches(3, 6, forward=True)

forward permet de changer la taille à la volée.

Si vous avez des problèmes avec des bordures trop grandes dans l'image créée, vous pouvez les ajuster soit avec :

plt.tight_layout()
#ou :
plt.tight_layout(pad=2)

ou :

fig.savefig('temp.png', dpi=fig.dpi, bbox_inches='tight')
#ou :
fig.savefig('temp.png', dpi=fig.dpi, bbox_inches='tight', pad_inches=0.5)

La première option minimise simplement la disposition et les bordures, et la deuxième option permet d'ajuster manuellement un peu les bordures. Ces astuces m'ont aidé au moins à résoudre mon problème d'images différentes entre savefig() et show().

33voto

doug Points 29567

Vous rendez vos graphiques matplotlib à différents dispositifs (par exemple, à l'écran via Quartz par rapport à un fichier via pdf en utilisant des fonctions différentes (plot par rapport à savefig) dont les paramètres sont presque les mêmes, cependant les valeurs par défaut pour ces paramètres ne sont pas les mêmes pour les deux fonctions.

Autrement dit, les paramètres par défaut de savefig sont différents de ceux par défaut de affichage.

Les aligner est simple si vous le faites dans le fichier de configuration matplotlib. Le fichier modèle est inclus dans le package source, et nommé matplotlibrc.template. Si vous n'en avez pas créé un lorsque vous avez installé matplotlib, vous pouvez obtenir ce modèle à partir de la source de matplotlib, ou depuis le site web de matplotlib.

Une fois que vous avez personnalisé ce fichier comme vous le souhaitez, renommez-le en matplotlibrc (pas d'extension) et enregistrez-le dans le répertoire .matplotlib (notez le point '.' devant) qui devrait être dans votre répertoire personnel.

Les paramètres de configuration pour enregistrer les figures commencent à environ la ligne 314 dans le matplotlibrc.template fourni (la première ligne avant cette section est: ### ENREGISTREMENT DES FIGURES).

En particulier, vous voudrez examiner ces paramètres:

savefig.dpi       : 100         # points par pouce de la figure
savefig.facecolor : white       # couleur de fond de la figure lors de l'enregistrement
savefig.edgecolor : white       # couleur de contour de la figure lors de l'enregistrement
savefig.extension : auto        # quelle extension utiliser pour savefig('foo'), ou 'auto'

En dessous de ces lignes sont les réglages pour le type de police et divers paramètres spécifiques au format d'image.

Ces mêmes paramètres pour l'affichage, c'est-à-dire, PLT.show(), commencent à environ la ligne 277 dans le matplotlibrc.template (cette section précédée par la ligne: ### FIGURE):

figure.figsize   : 8, 6          
figure.dpi       : 80            
figure.facecolor : 0.75       
figure.edgecolor : white     

Comme vous pouvez le voir en comparant les valeurs de ces deux blocs de paramètres, les valeurs par défaut pour le même attribut de la figure sont différentes pour savefig par rapport à affichage (show).

4voto

Karmel Points 1377

J'ai corrigé cela dans ma source matplotlib, mais ce n'est pas une solution très élégante. Cependant, si vous êtes comme moi, très attentif à l'apparence du graphique, cela en vaut la peine.

Le problème semble se situer dans les backends de rendu ; ils obtiennent chacun les bonnes valeurs pour l'épaisseur de ligne, la taille de la police, etc., mais cela ressort légèrement plus grand lorsqu'il est rendu en PDF ou en PNG qu'en étant rendu avec show().

J'ai ajouté quelques lignes à la source pour la génération de PNG, dans le fichier matplotlib/backends/backend_agg.py. Vous pourriez apporter des changements similaires pour chaque backend que vous utilisez, ou trouver un moyen de faire un changement plus intelligent en un seul endroit ;)

Ajouté à mon fichier matplotlib/backends/backend_agg.py :

    # Au début du fichier, lignes ajoutées 42 - 44
42  # @warning: CHANGÉ DE LA SOURCE pour dessiner des lignes plus fines
43  PATH_SCALAR = .8
44  FONT_SCALAR = .95

    # Dans la méthode draw_markers, lignes ajoutées 90 - 91
89  def draw_markers(self, *kl, **kw):
90      # @warning: CHANGÉ DE LA SOURCE pour dessiner des lignes plus fines
91      kl[0].set_linewidth(kl[0].get_linewidth()*PATH_SCALAR)
92      return self._renderer.draw_markers(*kl, **kw)

    # À la fin de la méthode draw_path, lignes ajoutées 131 - 132 :
130 else:
131     # @warning: CHANGÉ DE LA SOURCE pour dessiner des lignes plus fines
132     gc.set_linewidth(gc.get_linewidth()*PATH_SCALAR)
133     self._renderer.draw_path(gc, path, transform, rgbFace)

    # À la fin de la méthode _get_agg_font, ligne ajoutée 242 et le *FONT_SCALAR
241     font.clear()
242     # @warning: CHANGÉ DE LA SOURCE pour dessiner des lignes plus fines
243     size = prop.get_size_in_points()*FONT_SCALAR
244     font.set_size(size, self.dpi)

Donc cela convient à mes besoins pour l'instant, mais, en fonction de ce que vous faîtes, vous voudrez peut-être implémenter des changements similaires dans d'autres méthodes. Ou trouver un moyen plus efficace de faire la même chose sans autant de changements de lignes!

Mise à jour : Après avoir publié un problème sur le projet matplotlib sur Github, j'ai pu identifier la source de mon problème : j'avais modifié le paramètre figure.dpi dans le fichier matplotlibrc. Si cette valeur est différente de la valeur par défaut, mes images savefig() sont différentes, même si je définis le dpi de savefig pour être le même que le dpi de la figure. Donc, au lieu de changer la source comme décrit ci-dessus, j'ai simplement laissé le paramètre figure.dpi par défaut à 80, et j'ai pu générer des images avec savefig() qui ressemblaient aux images de show().

Léon, aviez-vous également modifié ce paramètre ?

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