Obróć macierz za pomocą Matplotlib

Oct 29 2020

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

3 tmdavison Oct 29 2020 at 13:39

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

MiguelGonzalez Oct 30 2020 at 10:20

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()