Поверните матрицу с помощью Matplotlib

Oct 29 2020

Я поворачиваю матрицу тревоги (n = 20, хотя она может измениться) на 30 градусов вправо, используя методы преобразования Matplotlib .

Ошибка появляется из - за поворот проведенная из верхних , а не от основания. Я попытался инвертировать индекс через np.flip()или, ax.imshow(origin = 'lower')но он также инвертирует треугольник, поэтому мне нужно узнать, как установить исходную точку преобразования .

Дефинтли, вот что я хотел бы получить :

Обратите внимание, что маленькие квадраты, соответствующие диагональной матрице, будут превращены в треугольники. Можно ли это сделать? Может быть, методом imshow, который возвращает полпикселя? Остальные пиксели останутся прежними (деформированные квадратики).

Вот код для создания матрицы ( отправная точка ):

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

А вот код, который пытается его повернуть :

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

Я не использую класс Triangle в Matplotlib, потому что троичная диаграмма представлена ​​через операцию интерполяции, и я хочу представить исходные значения матрицы.

Я бы очень признателен за чью-нибудь помощь. Заранее большое спасибо.

Ответы

3 tmdavison Oct 29 2020 at 13:39

Вместо изменения источника преобразования перекоса вы можете связать его с преобразованием в направлении x, чтобы достичь нужного преобразования.

Обратите внимание, что skewпреобразование принимает угол в радианах (вы использовали его с градусами). Есть эквивалентное skew_degпреобразование, если вы хотите работать в градусах, но здесь я просто работаю в радианах.

Также обратите внимание, что я думаю, вы хотите иметь равнобедренный треугольник с основанием и высотой, равными 20 (или какому-либо другому, как вы выберете N), угол, который вы хотите, равен не 30 градусам, а на самом деле arctan (1/2) (= 26,56 град).

Сумма, которую нужно перевести в направлении x, составляет xtrans = N * np.tan(angle).

Вы можете легко связать преобразования в matplotlib. Здесь мы можем сначала перекосить, а потом перевести:

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

Обратите внимание, что этот сценарий работает для любого значения 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()

Для N = 20

А для N = 30

MiguelGonzalez Oct 30 2020 at 10:20

В итоге я получил равносторонний треугольник с масштабированием по оси Y. Здесь я показываю код.

Следовательно, он позволяет преобразовать матрицу в равносторонний треугольник , что отвечает на мой предыдущий вопрос:

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