Rotar una matriz con Matplotlib
Estoy rotando la matriz de ansiedad (n = 20, aunque podría cambiar) 30 grados hacia la derecha usando los métodos de transformación de Matplotlib .
El error aparece porque la rotación se realiza desde arriba y no desde la base. He intentado invertir el índice a través de np.flip()o, ax.imshow(origin = 'lower')pero también invierte el triángulo, por lo que necesito descubrir cómo establecer el punto de origen de la transformación .
Defintley, esto es lo que me gustaría obtener :
Tenga en cuenta que los pequeños cuadrados que conforman la matriz diagonal se convertirían en triángulos. ¿Podría hacerse esto? ¿Quizás mediante un método imshow que devuelve medio píxel? El resto de los pixeles permanecerían igual (pequeños cuadrados deformados).
Aquí está el código para generar la matriz ( punto de partida ):
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')
Y aquí está el código que intenta rotarlo :
im = ax.imshow(matrix, cmap = 'Spectral')
im.set_transform(mtransforms.Affine2D().skew(30, 0) + ax.transData)
ax.plot(transform = trans_data)
No estoy usando la clase Triangle de Matplotlib porque el diagrama ternario se representa a través de una operación de interpolación, y quiero representar los valores de la matriz original.
Realmente agradecería la ayuda de alguien. Muchas gracias por adelantado.
Respuestas
En lugar de cambiar el origen de la transformación sesgada, puede encadenarlo con una traslación en la dirección x para lograr la transformación que está buscando.
Tenga en cuenta que la skewtransformación toma un ángulo en radianes (lo estaba usando con grados). Hay una skew_degtransformación equivalente si quieres trabajar en grados, pero aquí solo trabajo en radianes.
Tenga en cuenta también que creo que desea tener un triángulo isósceles con base y altura iguales a 20 (o lo que elija N), el ángulo que desea no es de 30 grados, sino en realidad arctan (1/2) (= 26.56 grados).
La cantidad que necesitas trasladar en la dirección x es xtrans = N * np.tan(angle).
Puede encadenar transformaciones fácilmente en matplotlib. Aquí podemos sesgar primero, luego traducir:
mtransforms.Affine2D().skew(-angle, 0).translate(xtrans, 0)
Tenga en cuenta que este script funciona con cualquier valor 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()
Para N = 20
Y para N = 30
Finalmente obtengo un eje y de escala de triángulo equilátero Aquí muestro el código.
Por tanto, permite convertir una matriz en un triángulo equilátero , lo que responde a mi pregunta anterior:
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()