问题描述
我想绘制一个热图,其中输入数据不在典型的矩形间隔网格中。以下是一些示例数据:
import numpy as np
xmin = 6
xmax= 12
ymin = 0
x = np.linspace(xmin,xmax,100)
ymax = x**2
final = []
for i in range(len(ymax)):
yrange = np.linspace(0,ymax[i],100)
for j in range(len(yrange)):
intensity = np.random.rand()
final.append([x[i],yrange[j],intensity])
data_for_plotting = np.asarray(final) # (10000,3) shaped array
我想将强度(在颜色条中)绘制为表示位置的 (x,y) 的函数,我想在没有插值的情况下执行此操作。
这是我使用 matplotlib 的网格数据和线性插值的解决方案。
import matplotlib.pyplot as plt
from matplotlib.mlab import griddata
total_length = 100
x1 = np.linspace(min(data_for_plotting[:,0]),max(data_for_plotting[:,total_length)
y1 = np.linspace(min(data_for_plotting[:,1]),total_length)
z1 = griddata(data_for_plotting[:,0],data_for_plotting[:,1],2],x1,y1,interp='linear')
p=plt.pcolormesh(x1,z1,vmin = 0.,vmax=1.0,cmap='viridis')
clb = plt.colorbar(p)
plt.show()
我正在寻找一种没有插值的替代解决方案,因为我想在我的 x 和 y 位置(像素大小/矩形)中看到最小的测量单位。根据上面给出的示例数据,我预计像素的高度会随着 x 的值增大而增加。
解决方法
我不确定 matplotlib.mlab.griddata
是关于什么的。也许是一些非常旧的版本?
您可以使用 scipy.interpolate.griddata
,它需要其参数格式略有不同。 method='nearest'
关闭插值(默认 method='linear'
)。
以下是您的测试数据的外观(有关更多解释和示例,请参阅 griddata 的文档):
import matplotlib.pyplot as plt
from scipy.interpolate import griddata
import numpy as np
xmin = 6
xmax = 12
ymin = 0
x = np.linspace(xmin,xmax,100)
ymax = x ** 2
final = []
for i in range(len(ymax)):
yrange = np.linspace(0,ymax[i],100)
for j in range(len(yrange)):
intensity = np.random.rand()
final.append([x[i],yrange[j],intensity])
data_for_plotting = np.asarray(final) # (10000,3) shaped array
total_length = 100
x1 = np.linspace(min(data_for_plotting[:,0]),max(data_for_plotting[:,total_length)
y1 = np.linspace(min(data_for_plotting[:,1]),total_length)
grid_x,grid_y = np.meshgrid(x1,y1)
z1 = griddata(data_for_plotting[:,:2],data_for_plotting[:,2],(grid_x,grid_y),method='nearest')
img = plt.imshow(z1,extent=[x1[0],x1[-1],y1[0],y1[-1]],origin='lower',vmin=0,vmax=1,cmap='inferno',aspect='auto')
cbar = plt.colorbar(img)
plt.show()
另一种方法是为每个延长的像素创建一个矩形。请注意,这可能是一个相当慢的操作。如果确实需要,可以为每一列创建一个 pcolormesh
。
import matplotlib.pyplot as plt
from matplotlib.cm import ScalarMappable
import numpy as np
# ... create x and data_for_plotting as before
fig,ax = plt.subplots()
cmap = plt.get_cmap('inferno')
norm = plt.Normalize(0,1)
x_step = x[1] - x[0]
y_step = 0
for i,(xi,yi,intensity_i) in enumerate(data_for_plotting):
if i + 1 < len(data_for_plotting) and data_for_plotting[i + 1,0] == xi: # when False,the last y_step is reused
y_step = data_for_plotting[i + 1,1] - yi
ax.add_artist(plt.Rectangle((xi,yi),x_step,y_step,color=cmap(norm(intensity_i))))
cbar = plt.colorbar(ScalarMappable(cmap=cmap,norm=norm))
ax.set_xlim(x[0],x[-1])
ax.set_ylim(0,1].max())
plt.tight_layout()
plt.show()