Obróć macierz za pomocą Matplotlib
Ja obrotowy anxn matrycy (n = 20, ale może się zmieniać) o 30 stopni w prawo za pomocą matplotlib w transformacji metod.
Błąd pojawia się, ponieważ obrót jest perfomed od góry, a nie od podstawy. Próbowałem odwrócić indeks przez np.flip()lub, ax.imshow(origin = 'lower')ale to również odwraca trójkąt, więc muszę odkryć, jak ustawić punkt początkowy transformacji .
Defintley, oto co chciałbym uzyskać :
Zauważ, że małe kwadraty, które odpowiadają matrycy przekątnej, zostaną zamienione w trójkąty. Czy można to zrobić? Może metodą imshow, która zwraca pół piksela? Reszta pikseli pozostałaby taka sama (zdeformowane małe kwadraty).
Oto kod do generowania macierzy ( punkt początkowy ):
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')
A oto kod, który próbuje go obrócić :
im = ax.imshow(matrix, cmap = 'Spectral')
im.set_transform(mtransforms.Affine2D().skew(30, 0) + ax.transData)
ax.plot(transform = trans_data)
Nie używam klasy Triangle w Matplotlib, ponieważ diagram trójskładnikowy jest reprezentowany przez operację interpolacji i chcę przedstawić oryginalne wartości macierzy.
Naprawdę byłbym wdzięczny za pomoc. Z góry bardzo dziękuję.
Odpowiedzi
Zamiast zmieniać pochodzenie transformacji skośnej, możesz połączyć ją z tłumaczeniem w kierunku x, aby uzyskać przekształcenie, którego szukasz.
Zwróć uwagę, że skewtransformacja przyjmuje kąt w radianach (używałeś jej ze stopniami). Istnieje równoważna skew_degtransformacja, jeśli chcesz pracować w stopniach, ale tutaj pracuję tylko w radianach.
Zauważ również, że myślę, że chcesz mieć trójkąt równoramienny z podstawą i wysokością równą 20 (lub cokolwiek wybierzesz N), kąt, który chcesz, nie wynosi 30 stopni, ale w rzeczywistości arctan (1/2) (= 26,56 deg).
Kwota, którą musisz przetłumaczyć w kierunku x, to xtrans = N * np.tan(angle).
Możesz łatwo łączyć transformacje w łańcuchy w matplotlib. Tutaj możemy najpierw pochylić, a następnie przetłumaczyć:
mtransforms.Affine2D().skew(-angle, 0).translate(xtrans, 0)
Zwróć uwagę, że ten skrypt działa dla dowolnej wartości 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()
Dla N = 20
I dla N = 30
W końcu otrzymuję trójkąt równoboczny skalujący oś y, tutaj pokazuję kod.
Pozwala więc na przekształcenie macierzy w trójkąt równoboczny , co odpowiem na moje poprzednie pytanie:
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()