我正在分析样品的磁化映射。获得梯度及其方向后,我将它们绘制为HSV(从-π到π的方向从0到1映射到Hue,而Value是标准化梯度)由img_rgb = mpl.colors.hsv_to_rgb(img_hsv)
转换为RGB。
我设法使用vmin和vmax添加HSV颜色条,但这并没有显示渐变的大小:
plt.imshow(img_rgb, cmap='hsv', vmin=-180, vmax=180, extent=(0, 100, 0,100))
plt.xlabel('μm')
plt.ylabel('μm')
plt.colorbar()
理想情况下,我想添加一个色轮,它可以对方向和幅度进行编码(可能就像极坐标图一样?)。如果无法做到这一点,请添加一个2D图,该图扩展当前颜色条以包含x轴上的渐变幅度。
子图显然是可能的,但它们看起来像一个kludge。还有更好的方法吗?
答案 0 :(得分:2)
首先,如果您想要同时显示两个不同的参数,可以通过为它们分配两个不同的通道(例如红色和绿色)来实现。这可以通过规范化两个2d阵列并将其馈送到与this answer类似的imshow
堆叠来完成。
如果您满足于方形的2d色彩映射,则可以通过创建meshgrid
然后再次堆叠并提供给imshow
来以相同的方式获取此色彩映射:
from matplotlib import pyplot as plt
import numpy as np
##generating some data
x,y = np.meshgrid(
np.linspace(0,1,100),
np.linspace(0,1,100),
)
directions = (np.sin(2*np.pi*x)*np.cos(2*np.pi*y)+1)*np.pi
magnitude = np.exp(-(x*x+y*y))
##normalize data:
def normalize(M):
return (M-np.min(M))/(np.max(M)-np.min(M))
d_norm = normalize(directions)
m_norm = normalize(magnitude)
fig,(plot_ax, bar_ax) = plt.subplots(nrows=1,ncols=2,figsize=(8,4))
plot_ax.imshow(
np.dstack((d_norm,m_norm, np.zeros_like(directions))),
aspect = 'auto',
extent = (0,100,0,100),
)
bar_ax.imshow(
np.dstack((x, y, np.zeros_like(x))),
extent = (
np.min(directions),np.max(directions),
np.min(magnitude),np.max(magnitude),
),
aspect = 'auto',
origin = 'lower',
)
bar_ax.set_xlabel('direction')
bar_ax.set_ylabel('magnitude')
plt.show()
结果如下:
原则上同样的事情也应该是极地Axes
,但根据this github ticket中的评论,imshow
不支持极轴,我无法做{ {1}}填写整张光盘。
修改强>:
感谢ImportanceOfBeingErnest和his answer另一个问题(imshow
关键字做了它),现在这里使用color
在极轴上显示2d色图。有一些警告,最值得注意的是,pcolormesh
尺寸需要比colors
方向的meshgrid
小一个,否则颜色图有螺旋形式:
theta
这产生了这个数字:
答案 1 :(得分:0)
在尝试可视化表面梯度的径向分量和绝对分量时,我遇到了类似的问题。
我正在通过 hsv 将渐变的绝对值加上角度转换为颜色(使用色调作为角度,使用饱和度和值作为绝对值)。这与磁化图中的相同,因为可以使用任何矢量场代替梯度。下面的函数说明了这个想法。完整代码在答案末尾提供。
import matplotlib.colors
# gradabs is the absolute gradient value,
# gradang is the angle direction, z the vector field
# the gradient was calculated of
max_abs = np.max(gradabs)
def grad_to_rgb(angle, absolute):
"""Get the rgb value for the given `angle` and the `absolute` value
Parameters
----------
angle : float
The angle in radians
absolute : float
The absolute value of the gradient
Returns
-------
array_like
The rgb value as a tuple with values [0..1]
"""
global max_abs
# normalize angle
angle = angle % (2 * np.pi)
if angle < 0:
angle += 2 * np.pi
return matplotlib.colors.hsv_to_rgb((angle / 2 / np.pi,
absolute / max_abs,
absolute / max_abs))
# convert to colors via hsv
grad = np.array(list(map(grad_to_rgb, gradang.flatten(), gradabs.flatten())))
# reshape
grad = grad.reshape(tuple(list(z.shape) + [3]))
结果图如下。
显示表面梯度场的完整示例代码:
import numpy as np
import matplotlib.colors
import matplotlib.pyplot as plt
r = np.linspace(0, np.pi, num=100)
x, y = np.meshgrid(r, r)
z = np.sin(y) * np.cos(x)
fig = plt.figure()
ax = fig.add_subplot(1, 3, 1, projection='3d')
ax.plot_surface(x, y, z)
# ax.imshow(z)
ax.set_title("Surface")
ax = fig.add_subplot(1, 3, 2)
ax.set_title("Gradient")
# create gradient
grad_y, grad_x = np.gradient(z)
# calculate length
gradabs = np.sqrt(np.square(grad_x) + np.square(grad_y))
max_abs = np.max(gradabs)
# calculate angle component
gradang = np.arctan2(grad_y, grad_x)
def grad_to_rgb(angle, absolute):
"""Get the rgb value for the given `angle` and the `absolute` value
Parameters
----------
angle : float
The angle in radians
absolute : float
The absolute value of the gradient
Returns
-------
array_like
The rgb value as a tuple with values [0..1]
"""
global max_abs
# normalize angle
angle = angle % (2 * np.pi)
if angle < 0:
angle += 2 * np.pi
return matplotlib.colors.hsv_to_rgb((angle / 2 / np.pi,
absolute / max_abs,
absolute / max_abs))
# convert to colors via hsv
grad = np.array(list(map(grad_to_rgb, gradang.flatten(), gradabs.flatten())))
# reshape
grad = grad.reshape(tuple(list(z.shape) + [3]))
ax.imshow(grad)
n = 5
gx, gy = np.meshgrid(np.arange(z.shape[0] / n), np.arange(z.shape[1] / n))
ax.quiver(gx * n, gy * n, grad_x[::n, ::n], grad_y[::n, ::n])
# plot color wheel
# Generate a figure with a polar projection, inspired by
# https://stackoverflow.com/a/48253413/5934316
ax = fig.add_subplot(1, 3, 3, projection='polar')
n = 200 # the number of secants for the mesh
t = np.linspace(0, 2 * np.pi, n)
r = np.linspace(0, max_abs, n)
rg, tg = np.meshgrid(r, t)
c = np.array(list(map(grad_to_rgb, tg.T.flatten(), rg.T.flatten())))
cv = c.reshape((n, n, 3))
m = ax.pcolormesh(t, r, cv[:,:,1], color=c, shading='auto')
m.set_array(None)
ax.set_yticklabels([])
plt.show()