Faire un triangle de Pascal coloré en Python est un bon moyen de s’occuper alors que les vacances sont là. Je vais vous présenter plusieurs designs, mon préféré allant au dernier.
Alors oui, je sais, j’avais déjà proposé une méthode pour construire le triangle de Pascal dans ce post. Mais j’avais envie d’explorer de nouvelles contrées informatiques. Je ne voulais pas passer par \(\LaTeX\).
Un triangle de Pascal coloré en Python: les prémices
Faire un triangle de Pascal en Python, c’est pas trop compliqué. Mais rendre le résultat attrayant, joli, et donc en mode graphique, c’est mieux… Il y a plusieurs techniques:
- pygame (pas génial à mon goût),
- tkinter (beurk! pour si peu ?)
- via \(\LaTeX\) et TiKZ (mouais… mais bon! je veux éviter justement!)
- matplotlib… Ouais!
On va partir sur matplotlib!
Le cahier des charges est simple:
- un triangle de Pascal centré ou pas
- des couleurs de fond pour chaque “cases”
- des couleurs en fonction de la position du nombre par rapport au centre des lignes
- une sauvegarde en haute définition de l’image.
Je précise que je ne vais pas définir ce qu’est le triangle de Pascal: z’avez cas regarder sur wikipedia.
Un triangle de Pascal coloré en Python: les différentes propositions
Je vais vous présenter six scripts.
Un triangle de Pascal coloré en Python: script 1
import numpy as np import matplotlib.pyplot as plt import matplotlib.colors as mcolors def pascal_triangle(n): """Generate the first n rows of Pascal's triangle.""" triangle = np.zeros((n, n), dtype=int) for i in range(n): triangle[i, 0] = 1 for j in range(1, i + 1): triangle[i, j] = triangle[i - 1, j - 1] + triangle[i - 1, j] return triangle def plot_pascal_triangle(n): """Plot the first n rows of Pascal's triangle with color.""" triangle = pascal_triangle(n) fig, ax = plt.subplots(figsize=(10, 10)) ax.axis('off') # Define a color map colors = plt.cm.viridis(np.linspace(0, 1, n)) for i in range(n): for j in range(i + 1): x = i y = -i / 2 + j color = colors[i] intensity = 1 - abs(j - i / 2) / (i / 2 + 1) ax.text(y, -x, triangle[i, j], ha='center', va='center', bbox=dict(facecolor=color * intensity, edgecolor='none', boxstyle='round,pad=0.3')) plt.xlim(-n/2, n/2) plt.ylim(-n, 1) plt.gca().set_aspect('equal', adjustable='box') plt.savefig('triangle_de_pascal.png', dpi=300, bbox_inches='tight') plt.show() plot_pascal_triangle(10)
Bon, clairement, c’est joli mais pas ouf… On peut améliorer!
Script 2: cases carrées, triangle aligné à gauche
import numpy as np import matplotlib.pyplot as plt def pascal_triangle(n): """Generate the first n rows of Pascal's triangle.""" triangle = np.zeros((n, n), dtype=int) for i in range(n): triangle[i, 0] = 1 for j in range(1, i + 1): triangle[i, j] = triangle[i - 1, j - 1] + triangle[i - 1, j] return triangle def plot_pascal_triangle(n): """Plot the first n rows of Pascal's triangle with color.""" triangle = pascal_triangle(n) fig, ax = plt.subplots(figsize=(10, 10)) ax.axis('off') # Define a color map colors = plt.cm.viridis(np.linspace(0, 1, n)) max_width = max([len(str(triangle[i, j])) for i in range(n) for j in range(i + 1)]) for i in range(n): for j in range(i + 1): x = j y = -i color = colors[i] intensity = 1 - abs(j - i / 2) / (i / 2 + 1) rect = plt.Rectangle((x - 0.5, y - 0.5), 1, 1, facecolor=color * intensity, edgecolor='none') ax.add_patch(rect) ax.text(x, y, triangle[i, j], ha='center', va='center', fontsize=10) plt.xlim(-0.5, n - 0.5) plt.ylim(-n, 0.5) plt.gca().set_aspect('equal', adjustable='box') plt.savefig('triangle_de_pascal.png', dpi=300, bbox_inches='tight') plt.show() plot_pascal_triangle(10)
Cela commence à avoir de la gueule… Mais j’aime bien quand c’est centré!
Script 3: cases carrées, triangle centré
import numpy as np import matplotlib.pyplot as plt def pascal_triangle(n): """Generate the first n rows of Pascal's triangle.""" triangle = np.zeros((n, n), dtype=int) for i in range(n): triangle[i, 0] = 1 for j in range(1, i + 1): triangle[i, j] = triangle[i - 1, j - 1] + triangle[i - 1, j] return triangle def plot_pascal_triangle(n): """Plot the first n rows of Pascal's triangle with color.""" triangle = pascal_triangle(n) fig, ax = plt.subplots(figsize=(10, 10)) ax.axis('off') # Define a color map colors = plt.cm.viridis(np.linspace(0, 1, n)) for i in range(n): for j in range(i + 1): x = j - i / 2 y = -i color = colors[i] intensity = 1 - abs(j - i / 2) / (i / 2 + 1) rect = plt.Rectangle((x - 0.5, y - 0.5), 1, 1, facecolor=color * intensity, edgecolor='none') ax.add_patch(rect) ax.text(x, y, triangle[i, j], ha='center', va='center', fontsize=10) plt.xlim(-n/2 - 0.5, n/2 + 0.5) plt.ylim(-n, 0.5) plt.gca().set_aspect('equal', adjustable='box') plt.savefig('triangle_de_pascal.png', dpi=300, bbox_inches='tight') plt.show() plot_pascal_triangle(10)
Voilà! C’est centré, mais peut-être trop “carré” ! Non ?
Script 4: cases avec coins arrondis, cases qui se chevauchent
import numpy as np import matplotlib.pyplot as plt from matplotlib.patches import FancyBboxPatch def pascal_triangle(n): """Generate the first n rows of Pascal's triangle.""" triangle = np.zeros((n, n), dtype=int) for i in range(n): triangle[i, 0] = 1 for j in range(1, i + 1): triangle[i, j] = triangle[i - 1, j - 1] + triangle[i - 1, j] return triangle def plot_pascal_triangle(n): """Plot the first n rows of Pascal's triangle with color.""" triangle = pascal_triangle(n) fig, ax = plt.subplots(figsize=(10, 10)) ax.axis('off') # Define a color map colors = plt.cm.viridis(np.linspace(0, 1, n)) for i in range(n): for j in range(i + 1): x = j - i / 2 y = -i color = colors[i] intensity = 1 - abs(j - i / 2) / (i / 2 + 1) rect = FancyBboxPatch((x - 0.5, y - 0.5), 1, 1, boxstyle="round,pad=0.1,rounding_size=0.2", facecolor=color * intensity, edgecolor='none') ax.add_patch(rect) ax.text(x, y, triangle[i, j], ha='center', va='center', fontsize=10, color='white') plt.xlim(-n/2 - 0.5, n/2 + 0.5) plt.ylim(-n, 0.5) plt.gca().set_aspect('equal', adjustable='box') plt.savefig('triangle_de_pascal.png', dpi=300, bbox_inches='tight') plt.show() plot_pascal_triangle(10)
Script 5: cases à coins arrondis, nombres qui s’adaptent
import numpy as np import matplotlib.pyplot as plt from matplotlib.patches import FancyBboxPatch def pascal_triangle(n): """Generate the first n rows of Pascal's triangle.""" triangle = np.zeros((n, n), dtype=int) for i in range(n): triangle[i, 0] = 1 for j in range(1, i + 1): triangle[i, j] = triangle[i - 1, j - 1] + triangle[i - 1, j] return triangle def plot_pascal_triangle(n): """Plot the first n rows of Pascal's triangle with color.""" triangle = pascal_triangle(n) fig, ax = plt.subplots(figsize=(10, 10)) ax.axis('off') # Define a color map colors = plt.cm.viridis(np.linspace(0, 1, n)) box_width = 0.8 box_height = 0.8 rounding_size = 0.1 base_fontsize = 12 # Max font size for i in range(n): for j in range(i + 1): x = j - i / 2 y = -i color = colors[i] intensity = 1 - abs(j - i / 2) / (i / 2 + 1) rect = FancyBboxPatch((x - box_width / 2, y - box_height / 2), box_width, box_height, boxstyle=f"round,pad=0.1,rounding_size={rounding_size}", facecolor=color * intensity, edgecolor='none') ax.add_patch(rect) # Adjust font size based on number length number_str = str(triangle[i, j]) fontsize = min(base_fontsize, box_width * 30 / len(number_str)) ax.text(x, y, number_str, ha='center', va='center', fontsize=fontsize, color='white') plt.xlim(-n/2 - 1, n/2 + 1) plt.ylim(-n, 1) plt.gca().set_aspect('equal', adjustable='box') plt.savefig('triangle_de_pascal.png', dpi=300, bbox_inches='tight') plt.show() plot_pascal_triangle(10)
L’avantage de ce dernier code est que la taille des nombres s’adapte. Voici ce que donne l’image lorsque n = 30: