Xoay ma trận với Matplotlib

Oct 29 2020

Tôi đang xoay ma trận anxn (n = 20, mặc dù nó có thể thay đổi) 30 độ sang phải bằng cách sử dụng các phương pháp biến đổi của Matplotlib .

Các lỗi xuất hiện vì luân chuyển được perfomed từ trên xuống chứ không phải từ cơ sở. Tôi đã cố gắng đảo ngược chỉ mục qua np.flip()hoặc ax.imshow(origin = 'lower')nhưng nó cũng đảo ngược tam giác, vì vậy tôi cần khám phá cách đặt điểm gốc biến đổi .

Defintley, đây là những gì tôi muốn lấy :

Lưu ý rằng các hình vuông nhỏ tuân theo ma trận đường chéo sẽ được chuyển thành hình tam giác. Điều này có thể được thực hiện? Có thể bằng một phương thức imshow trả về một nửa pixel? Phần còn lại của các pixel sẽ giữ nguyên (hình vuông nhỏ bị biến dạng).

Đây là mã để tạo ma trận ( điểm bắt đầu ):

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

Và đây là đoạn mã đang cố gắng xoay nó:

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

Tôi không sử dụng lớp Triangle của Matplotlib vì biểu đồ bậc ba được biểu diễn thông qua một phép toán nội suy và tôi muốn biểu diễn các giá trị ma trận ban đầu.

Tôi thực sự đánh giá cao sự giúp đỡ của một số người. Cảm ơn bạn rất nhiều trước.

Trả lời

3 tmdavison Oct 29 2020 at 13:39

Thay vì thay đổi nguồn gốc của phép biến đổi xiên, bạn có thể xâu chuỗi nó với một phép dịch theo hướng x để đạt được phép biến đổi mà bạn đang tìm kiếm.

Lưu ý rằng skewphép biến đổi có một góc tính bằng radian (bạn đang sử dụng nó với độ). Có một skew_degphép biến đổi tương đương nếu bạn muốn làm việc theo độ, nhưng ở đây tôi chỉ làm việc bằng radian.

Cũng lưu ý rằng tôi nghĩ rằng bạn muốn có một tam giác cân với đáy và chiều cao đều bằng 20 (hoặc bất cứ điều gì bạn chọn N là), góc bạn muốn không phải là 30 độ, mà thực sự là arctan (1/2) (= 26,56 độ).

Số tiền bạn cần để dịch theo hướng x là xtrans = N * np.tan(angle).

Bạn có thể biến đổi chuỗi dễ dàng trong matplotlib. Ở đây chúng ta có thể xiên trước, sau đó dịch:

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

Lưu ý rằng tập lệnh này hoạt động với bất kỳ giá trị nào của 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()

Đối với N = 20

Và cho N = 30

MiguelGonzalez Oct 30 2020 at 10:20

Cuối cùng tôi đã có được một hình tam giác đều chia tỷ lệ y-axis. Ở đây tôi hiển thị mã.

Do đó, nó cho phép chuyển ma trận thành một tam giác đều , câu trả lời cho câu hỏi trước đây của tôi là gì:

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