Faire pivoter une matrice avec Matplotlib

Oct 29 2020

Je tourne la matrice anxn (n = 20, bien que cela puisse changer) de 30 degrés vers la droite en utilisant les méthodes de transformation de Matplotlib .

L' erreur apparaît car la rotation est effectuée par le haut et non par la base. J'ai essayé d'inverser l'indice via np.flip()ou, ax.imshow(origin = 'lower')mais cela inverse également le triangle, je dois donc découvrir comment définir le point d'origine de la transformation .

Defintley, voici ce que j'aimerais obtenir :

Notez que les petits carrés conformes à la matrice diagonale seraient transformés en triangles. Cela pourrait-il être fait? Peut-être par une méthode imshow qui renvoie un demi-pixel? Le reste des pixels resterait le même (petits carrés déformés).

Voici le code pour générer la matrice ( point de départ ):

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.transforms as mtransforms

matrix = np.random.rand(20,20)

# Generate a boolean matrix (same shape than 'matrix') and select lower triangle values:

condition = np.tril(np.ones((matrix.shape))).astype(np.bool)
triangle = np.where(condition, matrix, np.nan)

fig, ax = plt.subplots(figsize = (8,8))

ax.imshow(triangle, cmap = 'Spectral')

Et voici le code essayant de le faire pivoter :

im = ax.imshow(matrix, cmap = 'Spectral')
im.set_transform(mtransforms.Affine2D().skew(30, 0) + ax.transData)
ax.plot(transform = trans_data)

Je n'utilise pas la classe Triangle de Matplotlib car le diagramme ternaire est représenté à travers une opération d'interpolation, et je veux représenter les valeurs de la matrice d'origine.

J'apprécierais vraiment l'aide de quelqu'un. Merci beaucoup d'avance.

Réponses

3 tmdavison Oct 29 2020 at 13:39

Au lieu de changer l'origine de la transformation oblique, vous pouvez l'enchaîner avec une traduction dans la direction x pour obtenir la transformation que vous recherchez.

Notez que la skewtransformation prend un angle en radians (vous l'utilisiez avec des degrés). Il y a une skew_degtransformation équivalente si vous voulez travailler en degrés, mais ici je travaille juste en radians.

Notez également que je pense que vous voulez avoir un triangle isocèle avec une base et une hauteur toutes deux égales à 20 (ou ce que vous choisissez N pour être), l'angle que vous voulez n'est pas de 30 degrés, mais en fait arctan (1/2) (= 26,56 deg).

Le montant que vous devez traduire dans la direction x est de xtrans = N * np.tan(angle).

Vous pouvez enchaîner facilement les transformations dans matplotlib. Ici, nous pouvons d'abord biaiser, puis traduire:

mtransforms.Affine2D().skew(-angle, 0).translate(xtrans, 0)

Notez que ce script fonctionne pour n'importe quelle valeur de N.

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.transforms as mtransforms

N = 20
matrix = np.random.rand(N, N)

# Generate a boolean matrix (same shape than 'matrix') and select lower triangle values:

condition = np.tril(np.ones((matrix.shape))).astype(np.bool)
triangle = np.where(condition, matrix, np.nan)

fig, ax = plt.subplots(figsize = (8,8))

im = ax.imshow(triangle, cmap = 'Spectral')

angle = np.arctan(1/2)
xtrans = N * np.tan(angle)
im.set_transform(mtransforms.Affine2D().skew(-angle, 0).translate(xtrans, 0) + ax.transData)

ax.set_xlim(-0.5, N + 0.5)
plt.show()

Pour N = 20

Et pour N = 30

MiguelGonzalez Oct 30 2020 at 10:20

J'obtiens enfin un triangle équilatéral avec une mise à l'échelle de l'axe y. Ici, je montre le code.

Par conséquent, il permet de convertir une matrice en triangle équilatéral , de quoi répondre à ma question précédente:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.transforms as mtransforms
import matplotlib

bins = 50
Z = np.random.rand(bins, bins)

# Generate a boolean matrix (same shape than 'matrix') and select lower triangle values:
condition = np.tril(np.ones((Z.shape))).astype(np.bool)
Z = np.where(condition, Z, np.nan)

fig, ax = plt.subplots(figsize = (8,8))
im = ax.imshow(Z, cmap = 'Spectral')

# Required angles (in Rad)
alpha = np.arctan(1/2)        # 26 deg angle, in radians.
beta = np.arctan(np.pi/6)     # 30 deg angle, in radians.

# Coefficients:
xtrans = np.sin(beta) * bins
scale_y = np.cos(beta)     

# Transformation:
im.set_transform(mtransforms.Affine2D().skew      (-alpha, 0)
                                       .scale     (1,scale_y)
                                       .translate (xtrans, 0) 
                                        + ax.transData)

ax.set_ylim(bins,-5)
ax.set_xlim(-5,bins)

plt.show()