我编写了一个从大气模型输出中绘制垂直横截面的例程。一个例子如下所示。我想做的是显示两个垂直轴:在左边我在对数刻度上显示压力值,在右边我以千米为单位显示高度。我认为在模型水平位置显示高度会很好 - 这就是为什么它们是不规则间隔的。一切都很好,除了右边的标签在底部附近重叠。我发现我可以使用ax2.get_yticklabels()[index].set_visible(False)
隐藏特定标签。我的问题是:如何确定要隐藏的标签(索引)?我相信应该可以找出刻度标签的位置(在轴或图形坐标中)。然后我可以使用阈值距离,如
yp = -1
for t in ax2.get_yticklabels():
y = t.get_position().y0 # this doesn't yield any useful bbox!
if y-yp < threshold:
t.set_visible(False)
else:
yp = y
不幸的是,我还没有找到获取标签坐标的方法。任何提示?
以下是示例图:
以下是完成绘图的完整代码(数据是二维数组,x是纬度,y是压力值):
def plotZM(data, x, y, plotOpt=None):
"""Create a zonal mean contour plot of one variable
plotOpt is a dictionary with plotting options:
'scale_factor': multiply values with this factor before plotting
'units': a units label for the colorbar
'levels': use list of values as contour intervals
'title': a title for the plot
"""
if plotOpt is None: plotOpt = {}
# create figure and axes
fig = plt.figure()
ax1 = fig.add_subplot(111)
# scale data if requested
scale_factor = plotOpt.get('scale_factor', 1.0)
pdata = data * scale_factor
# determine contour levels to be used; default: linear spacing, 20 levels
clevs = plotOpt.get('levels', np.linspace(data.min(), data.max(), 20))
# map contour values to colors
norm=matplotlib.colors.BoundaryNorm(clevs, ncolors=256, clip=False)
# draw the (filled) contours
contour = ax1.contourf(x, y, pdata, levels=clevs, norm=norm)
# add a title
title = plotOpt.get('title', 'Vertical cross section')
ax1.set_title(title) # optional keyword: fontsize="small"
# add colorbar
# Note: use of the ticks keyword forces colorbar to draw all labels
fmt = matplotlib.ticker.FormatStrFormatter("%g")
cbar = fig.colorbar(contour, ax=ax1, orientation='horizontal', shrink=0.8,
ticks=clevs, format=fmt)
cbar.set_label(plotOpt.get('units', ''))
for t in cbar.ax.get_xticklabels():
t.set_fontsize("x-small")
# change font size of x labels
xlabels = ax1.get_xticklabels()
for t in xlabels:
t.set_fontsize("x-small")
# set up y axes: log pressure labels on the left y axis, altitude labels
# according to model levels on the right y axis
ax1.set_ylabel("Pressure [hPa]")
ax1.set_yscale('log')
ax1.set_ylim(y.max(), y.min())
subs = [1,2,5]
print "y_max/y_min = ", y.max()/y.min()
if y.max()/y.min() < 30.:
subs = [1,2,3,4,5,6,7,8,9]
loc = matplotlib.ticker.LogLocator(base=10., subs=subs)
ax1.yaxis.set_major_locator(loc)
fmt = matplotlib.ticker.FormatStrFormatter("%g")
ax1.yaxis.set_major_formatter(fmt)
ylabels = ax1.get_yticklabels()
for t in ylabels:
t.set_fontsize("x-small")
# calculate altitudes from pressure values (use fixed scale height)
z0 = 8.400 # scale height for pressure_to_altitude conversion [km]
altitude = z0 * np.log(1015.23/y)
# add second y axis for altitude scale
ax2 = ax1.twinx()
ax2.set_ylabel("Altitude [km]")
ax2.set_ylim(altitude.min(), altitude.max())
ax2.set_yticks(altitude)
fmt = matplotlib.ticker.FormatStrFormatter("%6.1f")
ax2.yaxis.set_major_formatter(fmt)
# tweak altitude labels
ylabels = ax2.get_yticklabels()
for i,t in enumerate(ylabels):
t.set_fontsize("x-small")
# show plot
plt.show()
答案 0 :(得分:3)
这是plotZM例程的更新版本,它将模型级别绘制到右侧的单独面板中,并使用高度轴的线性等距标记。添加了另一种选择来掩盖低于表面压力的区域。
此代码为“缩放安全”(即,当您放大绘图或平移它时,高度和压力标签会很好地改变,并且模型级别会一致地变化)。它还包含相当多的轴和标签调整,因此可能对其他人有用,作为matplotlib可以做的更复杂的例子。示例图如下所示。
def plotZM(data, x, y, plotOpt=None, modelLevels=None, surfacePressure=None):
"""Create a zonal mean contour plot of one variable
plotOpt is a dictionary with plotting options:
'scale_factor': multiply values with this factor before plotting
'units': a units label for the colorbar
'levels': use list of values as contour intervals
'title': a title for the plot
modelLevels: a list of pressure values indicating the model vertical resolution. If present,
a small side panel will be drawn with lines for each model level
surfacePressure: a list (dimension len(x)) of surface pressure values. If present, these will
be used to mask out regions below the surface
"""
# explanation of axes:
# ax1: primary coordinate system latitude vs. pressure (left ticks on y axis)
# ax2: twinned axes for altitude coordinates on right y axis
# axm: small side panel with shared y axis from ax2 for display of model levels
# right y ticks and y label will be drawn on axr if modelLevels are given, else on ax2
# axr: pointer to "right axis", either ax2 or axm
if plotOpt is None: plotOpt = {}
labelFontSize = "small"
# create figure and axes
fig = plt.figure()
ax1 = fig.add_subplot(111)
# scale data if requested
scale_factor = plotOpt.get('scale_factor', 1.0)
pdata = data * scale_factor
# determine contour levels to be used; default: linear spacing, 20 levels
clevs = plotOpt.get('levels', np.linspace(data.min(), data.max(), 20))
# map contour values to colors
norm=matplotlib.colors.BoundaryNorm(clevs, ncolors=256, clip=False)
# draw the (filled) contours
contour = ax1.contourf(x, y, pdata, levels=clevs, norm=norm)
# mask out surface pressure if given
if not surfacePressure is None:
ax1.fill_between(x, surfacePressure, surfacePressure.max(), color="white")
# add a title
title = plotOpt.get('title', 'Vertical cross section')
ax1.set_title(title)
# add colorbar
# Note: use of the ticks keyword forces colorbar to draw all labels
fmt = matplotlib.ticker.FormatStrFormatter("%g")
cbar = fig.colorbar(contour, ax=ax1, orientation='horizontal', shrink=0.8,
ticks=clevs, format=fmt)
cbar.set_label(plotOpt.get('units', ''))
for t in cbar.ax.get_xticklabels():
t.set_fontsize(labelFontSize)
# set up y axes: log pressure labels on the left y axis, altitude labels
# according to model levels on the right y axis
ax1.set_ylabel("Pressure [hPa]")
ax1.set_yscale('log')
ax1.set_ylim(10.*np.ceil(y.max()/10.), y.min()) # avoid truncation of 1000 hPa
subs = [1,2,5]
if y.max()/y.min() < 30.:
subs = [1,2,3,4,5,6,7,8,9]
y1loc = matplotlib.ticker.LogLocator(base=10., subs=subs)
ax1.yaxis.set_major_locator(y1loc)
fmt = matplotlib.ticker.FormatStrFormatter("%g")
ax1.yaxis.set_major_formatter(fmt)
for t in ax1.get_yticklabels():
t.set_fontsize(labelFontSize)
# calculate altitudes from pressure values (use fixed scale height)
z0 = 8.400 # scale height for pressure_to_altitude conversion [km]
altitude = z0 * np.log(1015.23/y)
# add second y axis for altitude scale
ax2 = ax1.twinx()
# change values and font size of x labels
ax1.set_xlabel('Latitude [degrees]')
xloc = matplotlib.ticker.FixedLocator(np.arange(-90.,91.,30.))
ax1.xaxis.set_major_locator(xloc)
for t in ax1.get_xticklabels():
t.set_fontsize(labelFontSize)
# draw horizontal lines to the right to indicate model levels
if not modelLevels is None:
pos = ax1.get_position()
axm = fig.add_axes([pos.x1,pos.y0,0.02,pos.height], sharey=ax2)
axm.set_xlim(0., 1.)
axm.xaxis.set_visible(False)
modelLev = axm.hlines(altitude, 0., 1., color='0.5')
axr = axm # specify y axis for right tick marks and labels
# turn off tick labels of ax2
for t in ax2.get_yticklabels():
t.set_visible(False)
label_xcoor = 3.7
else:
axr = ax2
label_xcoor = 1.05
axr.set_ylabel("Altitude [km]")
axr.yaxis.set_label_coords(label_xcoor, 0.5)
axr.set_ylim(altitude.min(), altitude.max())
yrloc = matplotlib.ticker.MaxNLocator(steps=[1,2,5,10])
axr.yaxis.set_major_locator(yrloc)
axr.yaxis.tick_right()
for t in axr.yaxis.get_majorticklines():
t.set_visible(False)
for t in axr.get_yticklabels():
t.set_fontsize(labelFontSize)
# show plot
plt.show()
答案 1 :(得分:2)
我宁愿不做这样的事情。这可能会产生问题,例如,在调整绘图窗口大小或更改输出图像的dpi时。它肯定会显得很尴尬。
你应该
如果您需要帮助,请询问。