简体   繁体   中英

Rotate a matrix with Matplotlib

I am rotating anxn matrix (n = 20, although it could change) 30 degrees rightwards using Matplotlib's transformation methods.

The error shows up because rotation is perfomed from the top and not from the base. I have tried to inverse the index through np.flip() or ax.imshow(origin = 'lower') but it also invert the triangle, so I need to discovered how to set the transformation origin point .

Defintley, this is what I would like to obtain :

2

Note that the little squares that conforms the diagonal matrix would be turned into triangles. Could this be done? Maybe by an imshow method that returns half a pixel? The rest of the pixeles would stay the same (deformed little squares).

Here is the code for generate the matrix ( starting point ):

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

1

And here is the code trying to rotate it:

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

I am not using Triangle class of Matplotlib because the ternary diagram is represented througout an interpolation operation, and I want to represent the original matrix values.

I'd really appreciate some one's help. Thank you very much in advance.

Instead of changing the origin of the skew transformation, you could chain it with a translation in the x direction to achieve the transformation you are looking for.

Note that the skew transform takes an angle in radians (you were using it with degrees). There is an equivalent skew_deg transform if you want to work in degrees, but here I just work in radians.

Note also that I think you want to have an isosceles triangle with base and height both equal to 20 (or whatever you choose N to be), the angle you want is not 30 degrees, but actually arctan(1/2) (=26.56deg).

The amount you need to translate in the x direction is xtrans = N * np.tan(angle) .

You can chain transforms easily in matplotlib. Here we can skew first, then translate:

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

Note that this script works for any value of 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()

For N = 20 在此处输入图片说明

And for N = 30 在此处输入图片说明

I finally obtain an equilateral triangle scaling y-axis.Here I show the code.

Therefore, it allows converting a matrix into an equilateral triangle , what answer my previous question:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM