Python 使用matplotlib平滑二维半球坐标绘图
我在半球上有一些n点(θ在(0,90)范围内,φ在(0,180)范围内)。我想有一个热图的二维图,因为三维图有遮挡。此外,由于n个点位于间隔处,因此平滑图(例如,高斯平滑)可能看起来更好 我的尝试:我发现matplotlib的Python 使用matplotlib平滑二维半球坐标绘图,python,matplotlib,plot,Python,Matplotlib,Plot,我在半球上有一些n点(θ在(0,90)范围内,φ在(0,180)范围内)。我想有一个热图的二维图,因为三维图有遮挡。此外,由于n个点位于间隔处,因此平滑图(例如,高斯平滑)可能看起来更好 我的尝试:我发现matplotlib的极坐标图,它看起来像我想要的,尽管(a)栅格坐标标记错误,(b)对于间隔点,它没有平滑 编辑:我的最小工作示例 import numpy as np import matplotlib.pyplot as plt def to_degrees(x): return
极坐标图
,它看起来像我想要的,尽管(a)栅格坐标标记错误,(b)对于间隔点,它没有平滑
编辑:我的最小工作示例
import numpy as np
import matplotlib.pyplot as plt
def to_degrees(x):
return x*np.pi/180.0
def get_projection(phi, lmda, phi_0=0.0, lmda_0=to_degrees(90.0)):
# Credits : https://en.wikipedia.org/wiki/Orthographic_map_projection
x = np.cos(phi)*np.sin(lmda - lmda_0)
y = np.cos(phi_0)*np.sin(phi) - np.sin(phi_0)*np.cos(phi)*np.cos(lmda-lmda_0)
return [x, y]
# Adding latitudes and longitudes to give the appearance of a sphere
latitudes = [60, 30, 0, -30, -60] #elevations
longitudes = [0, 30, 60, 90, 120, 150, 180] #azimuths
plt.gca().set_aspect('equal', adjustable='box')
for longitude in longitudes:
prev_point = get_projection(to_degrees(-90.), to_degrees(0))
for latitude in range(-90, 90):
curr_point = get_projection(to_degrees(latitude), to_degrees(longitude))
plt.plot([prev_point[0], curr_point[0]], [prev_point[1], curr_point[1]], 'k', alpha=0.3)
prev_point = curr_point
for latitude in latitudes:
prev_point = get_projection(to_degrees(latitude), to_degrees(0))
for longitude in range(0, 180):
curr_point = get_projection(to_degrees(latitude), to_degrees(longitude))
plt.plot([prev_point[0], curr_point[0]], [prev_point[1], curr_point[1]], 'k', alpha=0.3)
prev_point = curr_point
views = [[-60, 0], [60, 0]] # and similar points of the format [azimuth, elevation]
frequency = [0.5, 0.3] # and similar numbers in range [0,1] for heatmap
for view_idx in range(len(views)):
loc = get_projection(to_degrees(views[view_idx][0]), to_degrees(views[view_idx][1]))
plt.scatter(loc[0], loc[1], s=300, c=np.array(plt.cm.jet(frequency[view_idx])).reshape(1, -1))
plt.show()
得到这个
因为我有11-12个这样的点分布在整个半球,所以我也希望使热图平滑。基于
你可以创建一个网格,然后用一个函数计算颜色
将imshow与插值一起使用
我写了一个函数来解决这个问题
def create_gaussian_mesh(views,cmap_names,t_x,t_y,radii,ax):
"""
views: the points
cmap_names: for heatmap
t_x: the number of grids in x direction
t_y: the number of grids in y direction
radii: the radii of the Gaussians to plot
ax: the canvas
"""
def gaussian(view,radius):
# initialize a patch and grids
patch = np.empty((t_x,t_y))
patch[:,:] = np.nan
x = np.linspace(-1,1,t_x)
y = np.linspace(-1,1,t_y)
x_grid,y_grid = np.meshgrid(x, y)
loc = get_projection(to_degrees(view[0]),to_degrees(view[1]))
# threshold controls the size of the gaussian
circle_mask = (x_grid-loc[0])**2 + (y_grid-loc[1])**2 < radius
gaussian_value = np.exp((x_grid-loc[0])**2+(y_grid-loc[1])**2)
patch[circle_mask] = gaussian_value[circle_mask]
return patch
# modify the patch
for view,cmap_name,radius in zip(views,cmap_names,radii):
patch = gaussian(view,radius)
extent = -1,1,-1,1
cmap = plt.get_cmap(cmap_name)
ax.imshow(patch,cmap=cmap,alpha=.6,interpolation='bilinear',extent=extent)
其中x轴和y轴的刻度都已正确设置。代码的输出数字是
如@DizietAsahi所说,您需要提供一个包含玩具数据集(请参阅)的示例,请提供一个我们可以使用的示例。除此之外,例如,在极坐标系中,是否可以在视觉上接近您所要查找的内容(即使用
pcolormesh
绘制griddata
)?添加了我的尝试。谢谢,虽然我现在想平滑散点图,但看起来确实有点类似。这样做只是为了一个有限的圈子有点挑战性,而其他答案似乎无法解决这个问题。
import numpy as np
import matplotlib.pyplot as plt
to_degrees = lambda x: np.deg2rad(x)
def get_projection(phi, lmda, phi_0=0.0, lmda_0=to_degrees(90.0)):
# Credits : https://en.wikipedia.org/wiki/Orthographic_map_projection
x = np.cos(phi)*np.sin(lmda - lmda_0)
y = np.cos(phi_0)*np.sin(phi) - np.sin(phi_0)*np.cos(phi)*np.cos(lmda-lmda_0)
return x, y
# Adding latitudes and longitudes to give the appearance of a sphere
latitudes = [60, 30, 0, -30, -60] #elevations
longitudes = [0, 30, 60, 90, 120, 150, 180] #azimuths
fig,ax = plt.subplots(figsize=(8,8))
ax.set_aspect('equal', adjustable='box')
ax.set_xlim(-1,1)
ax.set_ylim(-1,1)
# set the right ticks
x_ticks = ['$%i\degree$' % ind for ind in np.linspace(0,180,10).astype(int)]
y_ticks = ['$%i\degree$' % ind for ind in np.linspace(-90,90,10).astype(int)]
ax.set_xticks(np.linspace(-1,1,10));ax.set_xticklabels(x_ticks)
ax.set_yticks(np.linspace(-1,1,10));ax.set_yticklabels(y_ticks)
for longitude in longitudes:
prev_point = get_projection(to_degrees(-90.), to_degrees(0))
for latitude in range(-90, 90):
curr_point = get_projection(to_degrees(latitude), to_degrees(longitude))
ax.plot([prev_point[0], curr_point[0]], [prev_point[1], curr_point[1]], 'k', alpha=0.3)
prev_point = curr_point
for latitude in latitudes:
prev_point = get_projection(to_degrees(latitude), to_degrees(0))
for longitude in range(0, 180):
curr_point = get_projection(to_degrees(latitude), to_degrees(longitude))
ax.plot([prev_point[0], curr_point[0]], [prev_point[1], curr_point[1]], 'k', alpha=0.3)
prev_point = curr_point
views = [[-60, 0], [60, 0], [20,10],[30,45]] # and similar points of the format [azimuth, elevation]
# instead of frequencies, you need a list of names of cmaps
cmap_names= ['gray','hot','cool','Greys']
# the radius of the gaussians to plot
radii = np.linspace(0.08,0.1,len(views))
create_gaussian_mesh(views,cmap_names,t_x=300,t_y=300,radii=radii,ax=ax)