Ruota una matrice con Matplotlib
Sto ruotando anxn matrix (n = 20, anche se potrebbe cambiare) di 30 gradi verso destra usando i metodi di trasformazione di Matplotlib .
L' errore si manifesta perché la rotazione è eseguita dall'alto e non dalla base. Ho provato a invertire l'indice attraverso np.flip()o ax.imshow(origin = 'lower')ma anche invertire il triangolo, quindi ho bisogno di scoprire come impostare il punto di origine della trasformazione .
Defintley, questo è quello che vorrei ottenere :
Nota che i quadratini che conformano la matrice diagonale verrebbero trasformati in triangoli. Potrebbe essere fatto? Forse con un metodo imshow che restituisce mezzo pixel? Il resto dei pixel rimarrebbe lo stesso (quadratini deformati).
Ecco il codice per generare la matrice ( punto di partenza ):
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')
Ed ecco il codice che prova a ruotarlo :
im = ax.imshow(matrix, cmap = 'Spectral')
im.set_transform(mtransforms.Affine2D().skew(30, 0) + ax.transData)
ax.plot(transform = trans_data)
Non sto usando la classe Triangle di Matplotlib perché il diagramma ternario è rappresentato attraverso un'operazione di interpolazione e voglio rappresentare i valori della matrice originale.
Apprezzerei davvero l'aiuto di qualcuno. Grazie mille in anticipo.
Risposte
Invece di cambiare l'origine della trasformazione obliqua, potresti concatenarla con una traduzione nella direzione x per ottenere la trasformazione che stai cercando.
Nota che la skewtrasformazione prende un angolo in radianti (lo stavi usando con gradi). C'è una skew_degtrasformazione equivalente se vuoi lavorare in gradi, ma qui lavoro solo in radianti.
Nota anche che penso che tu voglia avere un triangolo isoscele con base e altezza entrambi uguali a 20 (o qualunque cosa tu scelga N), l'angolo che desideri non è 30 gradi, ma in realtà arctan (1/2) (= 26,56 deg).
L'importo che devi tradurre nella direzione x è xtrans = N * np.tan(angle).
Puoi concatenare facilmente le trasformazioni in matplotlib. Qui possiamo prima inclinare, quindi tradurre:
mtransforms.Affine2D().skew(-angle, 0).translate(xtrans, 0)
Nota che questo script funziona per qualsiasi valore di 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()
Per N = 20
E per N = 30
Finalmente ottengo un triangolo equilatero che scala l'asse y.Qui mostro il codice.
Pertanto, consente di convertire una matrice in un triangolo equilatero , quale risposta alla mia domanda precedente:
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()