[PYTHON] (Matplotlib) Je veux dessiner un graphique avec une taille spécifiée en pixels

introduction

Ceci explique comment spécifier la taille (largeur / hauteur) de la zone de tracé en unités de pixels ** pour le graphique créé par matplotlib comme suit.

top.png

Environnement d'exécution (Google Colab.)

Mise en garde

Dans le cas de l'environnement Jupyter (Google Colab. Environment), ** par plt.show (...) ** Image PNG affichée dans la cellule de résultat d'exécution ** et avec plt.savefig (...) ** ** La taille de l'image PNG ** qui est sortie sous forme de fichier est différente ** </ font>.

Plus précisément, l'image ** PNG affichée dans la cellule de résultat d'exécution ** sera ** les marges environnantes sont automatiquement coupées </ font> **. Je vais.

Par exemple, si le code suivant est automatisé dans l'environnement Google Colab., L'image affichée dans la cellule de sortie est de 348 $ \ fois 270 $ (px), tandis que l'image enregistrée sous le nom test.png est de 400 $ \ fois 300. Ce sera $ (px).

python


import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0,20,100) #Exemple de données pour le dessin
y = x ** 0.5              #Exemple de données pour le dessin

fig = plt.figure(dpi=100, figsize=(4,3))
plt.plot(x,y)
plt.savefig('test.png') #Sortie dans un fichier 400 x 300 px
plt.show()              #348 x 270 px affichés dans la cellule de sortie

--figsize = (4,3) spécifie la" largeur "et la" hauteur "de l'image en ** unités pouces **. --Dans dpi = 100," Point par pouce (= nombre de points par pouce (nombre de pixels) "est spécifié.

  • La taille de l'image de sortie est ** largeur ** est de 4 $ , \ mathrm {pouces} \ fois 100 , \ mathrm {dpi} = 400 , \ mathrm {pixel} $, ** hauteur ** est de 3 $ \ , \ mathrm {inch} \ times 100 , \ mathrm {dpi} = 300 , \ mathrm {pixel} $ ... Cela devrait être, mais il est affiché dans la cellule de sortie L'image sera un peu plus petite </ font> avec les marges coupées.

A partir de maintenant, nous allons passer aux ** images cibles qui sont sorties sous forme de fichiers ** avec plt.savefig (...).

Je veux trouver la taille de la zone de tracé (nette) au lieu de la taille de l'image

La taille de l'image (en pixels) pourrait être calculée à partir de la «taille» et du «PPP» de la «figure» spécifiée en pouces, comme décrit ci-dessus. Cela peut être calculé à partir d'une instance de «figure» («fig») comme suit:

Calculer la taille de l'image (en pixels)


fig_w_px = int(fig.get_figwidth()  * fig.get_dpi())  
fig_h_px = int(fig.get_figheight() * fig.get_dpi())
print(f'■ Fig size  {fig_w_px} x {fig_h_px} [px]')

Tout d'abord, ici, au lieu de la taille globale de cette image, la taille de la zone de tracé (nette) entourée de ** cadre rouge ** </ font> ** comme suit: Nous découvrirons à quoi ressemble ** (en pixels).

top2.png

La taille de la zone de traçage (en pixels) peut être calculée en obtenant la valeur de l'objet Axes (ʻax) comme suit: De plus, comme le japonais est utilisé dans la figure, veuillez d'abord exécuter ! Pip install japanize-matplotlib` pour installer la bibliothèque dans Google Colab. Environnement etc.

Calculer la taille de la zone de traçage (en pixels)


import numpy as np
import japanize_matplotlib 
import matplotlib.pyplot as plt

x = np.linspace(0,20,100) #Exemple de données pour le dessin
y = x ** 0.5              #Exemple de données pour le dessin

fig = plt.figure(dpi=100, figsize=(4,3))
ax = plt.gca()
ax.plot(x,y)
ax.set_xlabel('contribution',fontsize=12)
ax.set_ylabel('production',fontsize=12)
plt.savefig('foo.png')

#Taille de la figure (image entière)
fig_w_px = int(fig.get_figwidth()  * fig.get_dpi())  
fig_h_px = int(fig.get_figheight() * fig.get_dpi())
print(f'■ Fig size   {fig_w_px} x {fig_h_px} [px]')

#Taille de l'axe (zone de tracé)
ax_size_inch = ax.figure.get_size_inches()
ax_w_inch = ax_size_inch[0] * (ax.figure.subplotpars.right - ax.figure.subplotpars.left)
ax_h_inch = ax_size_inch[1] * (ax.figure.subplotpars.top - ax.figure.subplotpars.bottom)
ax_w_px = int( ax_w_inch * fig.get_dpi() )  
ax_h_px = int( ax_h_inch * fig.get_dpi() )
print(f'■ Axis size  {ax_w_px } x {ax_h_px } [px]')

Le résultat de l'exécution est le suivant. De plus, si vous ouvrez le fichier de sortie foo.png avec un logiciel d'édition d'image, etc. et vérifiez la taille de la zone de traçage, cela correspond sûrement au résultat suivant.

Résultat d'exécution


■ Fig size   400 x 300 [px]
■ Axis size  310 x 226 [px]

Description du programme

--ʻAx.figure.get_size_inches () `, la taille de la zone comprenant la taille globale de l'objet Axes (= ** échelles et étiquettes pour chaque axe (caractères tels que" entrée "et" sortie ") ** ) Est obtenu en pouces.

--Dans ʻax.figure.subplotpars.left, il s'agit d'une valeur (0,0 $ à 1,0 $) qui représente la ** position du bord gauche ** de la zone de tracé lorsque la largeur totale de l'objet Axes est de ** 1,0 $. De plus, ʻax.figure.subplotpars.right est une valeur qui représente ** la position la plus à droite de la zone de traçage **.

  • Ici, la différence entre les deux ʻax.figure.subplotpars.right --ax.figure.subplotpars.left` est la largeur de la zone de traçage où la ** largeur de l'objet Axes est ** $ 1.0 $ Il représente le ratio de **.

  • Afin d'obtenir la largeur de la zone de traçage en ** unités pouces **, la largeur totale de l'objet Axes ʻax_size_inch [0] (en pouces) et la largeur (ratio) de la zone de traçage ʻax.figure.subplotpars.right - Multiplier par ax.figure.subplotpars.left et stocker dans ʻax_w_inch`.

  • Afin de convertir les unités pouces en unités de pixels, ʻax_w_inch est multiplié par la résolution fig.get_dpi () ʻet stocké dans ʻax_w_px`.

Je souhaite dessiner un graphique en spécifiant la taille de la zone de traçage en pixels

J'ai pu ** trouver la taille de la zone de tracé en pixels **.

Cette fois, au contraire, ** spécifiez la taille de la zone de traçage en pixels ** et tracez un graphique. Le code suivant est un exemple qui dessine un graphique afin que la zone de tracé soit de 400 $ \ fois 300 $ (px).

--Référence: Démo Axes de taille fixe @ matplotlib.org

La cause est inconnue, mais à la fin du programme, si la taille de la zone de tracé est recalculée et sortie, elle sera ʻ Taille de l'axe 387 x 302 [px] `. Cependant, lorsque j'ai mesuré la taille de la zone de tracé pour l'image de sortie réelle (foo.png), elle était correctement de 400 $ \ fois 300 $ (px).

Sortie graphique en spécifiant la taille de la zone de tracé en pixels


import numpy as np
import japanize_matplotlib 
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import Divider, Size #ajouter à
from mpl_toolkits.axes_grid1.mpl_axes import Axes #ajouter à

x = np.linspace(0,20,100) #Exemple de données pour le dessin
y = x ** 0.5              #Exemple de données pour le dessin

ax_w_px = 400  #Spécifiez la largeur de la zone de traçage en pixels
ax_h_px = 300  #Spécifiez la hauteur de la zone de tracé en pixels

#Traitement pour la spécification de taille ↓ ↓ À partir de là ↓ ↓
fig_dpi = 100
ax_w_inch = ax_w_px / fig_dpi
ax_h_inch = ax_h_px / fig_dpi
ax_margin_inch = (0.5, 0.5, 0.5, 0.5)  # Left,Top,Right,Bottom [inch]

fig_w_inch = ax_w_inch + ax_margin_inch[0] + ax_margin_inch[2] 
fig_h_inch = ax_h_inch + ax_margin_inch[1] + ax_margin_inch[3]

fig = plt.figure( dpi=fig_dpi, figsize=(fig_w_inch, fig_h_inch))
ax_p_w = [Size.Fixed(ax_margin_inch[0]),Size.Fixed(ax_w_inch)]
ax_p_h = [Size.Fixed(ax_margin_inch[1]),Size.Fixed(ax_h_inch)]
divider = Divider(fig, (0.0, 0.0, 1.0, 1.0), ax_p_w, ax_p_h, aspect=False)
ax = Axes(fig, divider.get_position())
ax.set_axes_locator(divider.new_locator(nx=1,ny=1))
fig.add_axes(ax)
#Traitement pour la spécification de taille ↑↑ Jusqu'ici ↑↑

ax.plot(x,y)
ax.set_xlabel('contribution',fontsize=12)
ax.set_ylabel('production',fontsize=12)
plt.savefig('foo.png')

#Taille de la figure (image entière)
fig_w_px = int(fig.get_figwidth()  * fig.get_dpi())  
fig_h_px = int(fig.get_figheight() * fig.get_dpi())
print(f'■ Fig size   {fig_w_px} x {fig_h_px} [px]')

#Taille de l'axe (zone de tracé)
ax_size_inch = ax.get_figure().get_size_inches()
ax_w_inch = ax_size_inch[0] * (ax.figure.subplotpars.right - ax.figure.subplotpars.left)
ax_h_inch = ax_size_inch[1] * (ax.figure.subplotpars.top - ax.figure.subplotpars.bottom)
ax_w_px = int( ax_w_inch * fig.get_dpi() )  
ax_h_px = int( ax_h_inch * fig.get_dpi() )
print(f'■ Axis size  {ax_w_px } x {ax_h_px } [px]') 
#La sortie d'impression ci-dessus ne donne pas 400 x 300,
#Image réelle ('foo.png'), La taille de la zone de traçage est de 400 x 300

Recommended Posts