Pour certains tracés de cadrans solaires, j’ai eu besoin de générer des graphiques en pdf, pour lesquels 1 unité de graduation mesure exactement 1 cm. Cela revient à trouver comment imposer les dimensions du cadre du graphique. Voici la méthode à laquelle j’ai abouti avec Python et le module Matplotlib :
Dans la commande fig = plt.figure(), le mot-clé figsize=(largeur,hauteur) permet d’imposer les dimensions de la figure, mais pour le cadre du graphique il n’existe pas à ma connaissance de commande similaire.
J’utilise la commande plt.subplots_adjust() dans lesquelles on entre les valeurs des marges latérales, supérieure et inférieure. Il faut soi-même calculer les dimensions des marges, en créant les variables correspondantes.
import matplotlib.pyplot as plt
# limites des graduations :
xmin, xmax = -2, 10 # donc largeur 12 cm
ymin, ymax = 20, 38 # donc hauteur 18 cm
inch = 2.54 # conversion des cm en pouces
fig_width = 29.7 / inch
fig_height = 21 / inch
marge_G = 2 / inch
largeur_axe = 12 / inch # 12 cm, en cohérence avec xmin et xmax
hauteur_axe = 18 / inch # 18 cm, en cohérence avec ymin et ymax
marge_D=fig_width-marge_G-largeur_axe
marge_B=marge_G
marge_H=fig_height-marge_B-hauteur_axe
fig = plt.figure(figsize=(fig_width, fig_height))
ax1 = plt.subplot(1, 1, 1)
ax1.set_xlim(xmin,xmax)
ax1.set_ylim(ymin,ymax)
# ajustement des dimensions de l'axe :
# les valeurs "left", "right", "bottom" et "top" sont des % entre 0 et 1
plt.subplots_adjust(
left=marge_G / fig_width,
right=1-marge_D/fig_width,
bottom= marge_B / fig_height,
top= 1 - marge_H / fig_height,
)
Pour contrôler le résultat final, j’ai trouvé dans le livre de Nicolas Rougier (Scientific Visualization: Python + Matplotlib) un script qui trace des règles verticale et horizontale en taille réelle :
# Cette partie trace un quadrillage réglé en cm, pour vérifier les dimensions
import matplotlib.ticker as ticker
import numpy as np
class Ruler:
""" Ruler add a whole figure axis whose ticks indicate figure
dimensions and adapt itself to figure resize event.
"""
def __init__(self, fig=None):
self.fig = fig or plt.gcf()
self.ax = None
self.show()
def show(self):
if self.ax is None:
ax = fig.add_axes([0, 0, 1, 1], zorder=-10, facecolor="None")
ax.spines["right"].set_visible(False)
ax.spines["bottom"].set_visible(False)
ax.xaxis.set_minor_locator(ticker.MultipleLocator(0.1))
ax.tick_params(
axis="x", which="both", labelsize="x-small", direction="in", pad=-15
)
ax.xaxis.tick_top()
ax.yaxis.set_minor_locator(ticker.MultipleLocator(0.1))
ax.yaxis.tick_left()
ax.tick_params(
axis="y", which="both", labelsize="x-small", direction="in", pad=-8
)
ax.yaxis.tick_left()
for label in ax.yaxis.get_ticklabels():
label.set_horizontalalignment("left")
self.text = ax.text(
0.5, 0.4, "cm", ha="center", va="center", size="x-small"
)
ax.grid(linestyle="--", linewidth=0.5)
self.ax = ax
self.update()
plt.connect("resize_event", self.update)
def update(self, *args):
inch = 2.54
width_cm = self.fig.get_figwidth() * inch
height_cm = self.fig.get_figheight() * inch
n = int(width_cm) + 1
self.ax.set_xlim(0, width_cm)
self.ax.set_xticks(np.arange(n))
self.ax.set_xticklabels([""] + ["%d" % x for x in np.arange(1, n)])
markersize = self.ax.xaxis.get_ticklines(True)[0].get_markersize()
for line in self.ax.xaxis.get_ticklines(True)[2::9]:
line.set_markersize(1.5 * markersize)
n = int(height_cm) + 1
self.ax.set_ylim(height_cm, 0)
self.ax.set_yticks(np.arange(n))
self.ax.set_yticklabels([""] + ["%d" % y for y in np.arange(1, n)])
markersize = self.ax.yaxis.get_ticklines(True)[0].get_markersize()
for line in self.ax.yaxis.get_ticklines(True)[1::9]:
line.set_markersize(1.5 * markersize)
ruler=Ruler()
Un autre moyen de contrôler les dimensions du cadre graphique : ouvrir le pdf obtenu avec un logiciel de dessin vectoriel (comme par exemple Inkscape, gratuit et multiplateforme), en utilisant l’outil « mesure » (raccourci clavier « M »).
Code Python du script complet :
Be First to Comment