0 總述
imshow()允許你將圖像(將進行顏色映射——基于norm和cmap——的2D數組或將按原樣使用的3D RGB(A)的數組)渲染到數據空間中的矩形區域。最終渲染中圖像的方向由原點和范圍關鍵字參數(以及生成的AxesImage實例上的屬性)和Axes的數據限制控制。
extent關鍵字參數控制數據坐標中的邊界框,圖像將填充該邊界框在數據坐標中指定為(左、右、上、下),origin關鍵字參數控制圖像填充該邊界框的方式,最終渲染圖像中的方向也受Axes限制的影響。
提示
下面的大部分代碼用于向繪圖添加標簽和信息文本,所描述的原點和范圍的影響可以在圖中看到,而無需遵循所有的代碼細節。
為了快速理解,你可能希望跳過下面的代碼詳細信息,直接繼續討論結果。
import matplotlib.pyplot as plt
import numpy as npfrom matplotlib.gridspec import GridSpecdef index_to_coordinate(index, extent, origin):"""Return the pixel center of an index."""left, right, bottom, top = extenthshift = 0.5 * np.sign(right - left)left, right = left + hshift, right - hshiftvshift = 0.5 * np.sign(top - bottom)bottom, top = bottom + vshift, top - vshiftif origin == 'upper':bottom, top = top, bottomreturn {"[0, 0]": (left, bottom),"[M', 0]": (left, top),"[0, N']": (right, bottom),"[M', N']": (right, top),}[index]def get_index_label_pos(index, extent, origin, inverted_xindex):"""Return the desired position and horizontal alignment of an index label."""if extent is None:extent = lookup_extent(origin)left, right, bottom, top = extentx, y = index_to_coordinate(index, extent, origin)is_x0 = index[-2:] == "0]"halign = 'left' if is_x0 ^ inverted_xindex else 'right'hshift = 0.5 * np.sign(left - right)x += hshift * (1 if is_x0 else -1)return x, y, haligndef get_color(index, data, cmap):"""Return the data color of an index."""val = {"[0, 0]": data[0, 0],"[0, N']": data[0, -1],"[M', 0]": data[-1, 0],"[M', N']": data[-1, -1],}[index]return cmap(val / data.max())def lookup_extent(origin):"""Return extent for label positioning when not given explicitly."""if origin == 'lower':return (-0.5, 6.5, -0.5, 5.5)else:return (-0.5, 6.5, 5.5, -0.5)def set_extent_None_text(ax):ax.text(3, 2.5, 'equals\nextent=None', size='large',ha='center', va='center', color='w')def plot_imshow_with_labels(ax, data, extent, origin, xlim, ylim):"""Actually run ``imshow()`` and add extent and index labels."""im = ax.imshow(data, origin=origin, extent=extent)# extent labels (left, right, bottom, top)left, right, bottom, top = im.get_extent()if xlim is None or top > bottom:upper_string, lower_string = 'top', 'bottom'else:upper_string, lower_string = 'bottom', 'top'if ylim is None or left < right:port_string, starboard_string = 'left', 'right'inverted_xindex = Falseelse:port_string, starboard_string = 'right', 'left'inverted_xindex = Truebbox_kwargs = {'fc': 'w', 'alpha': .75, 'boxstyle': "round4"}ann_kwargs = {'xycoords': 'axes fraction','textcoords': 'offset points','bbox': bbox_kwargs}ax.annotate(upper_string, xy=(.5, 1), xytext=(0, -1),ha='center', va='top', **ann_kwargs)ax.annotate(lower_string, xy=(.5, 0), xytext=(0, 1),ha='center', va='bottom', **ann_kwargs)ax.annotate(port_string, xy=(0, .5), xytext=(1, 0),ha='left', va='center', rotation=90,**ann_kwargs)ax.annotate(starboard_string, xy=(1, .5), xytext=(-1, 0),ha='right', va='center', rotation=-90,**ann_kwargs)ax.set_title(f'origin: {origin}')# index labelsfor index in ["[0, 0]", "[0, N']", "[M', 0]", "[M', N']"]:tx, ty, halign = get_index_label_pos(index, extent, origin,inverted_xindex)facecolor = get_color(index, data, im.get_cmap())ax.text(tx, ty, index, color='white', ha=halign, va='center',bbox={'boxstyle': 'square', 'facecolor': facecolor})if xlim:ax.set_xlim(*xlim)if ylim:ax.set_ylim(*ylim)def generate_imshow_demo_grid(extents, xlim=None, ylim=None):N = len(extents)fig = plt.figure(tight_layout=True)fig.set_size_inches(6, N * (11.25) / 5)gs = GridSpec(N, 5, figure=fig)columns = {'label': [fig.add_subplot(gs[j, 0]) for j in range(N)],'upper': [fig.add_subplot(gs[j, 1:3]) for j in range(N)],'lower': [fig.add_subplot(gs[j, 3:5]) for j in range(N)]}x, y = np.ogrid[0:6, 0:7]data = x + yfor origin in ['upper', 'lower']:for ax, extent in zip(columns[origin], extents):plot_imshow_with_labels(ax, data, extent, origin, xlim, ylim)columns['label'][0].set_title('extent=')for ax, extent in zip(columns['label'], extents):if extent is None:text = 'None'else:left, right, bottom, top = extenttext = (f'left: {left:0.1f}\nright: {right:0.1f}\n'f'bottom: {bottom:0.1f}\ntop: {top:0.1f}\n')ax.text(1., .5, text, transform=ax.transAxes, ha='right', va='center')ax.axis('off')return columns
1 默認范圍
首先,讓我們看一下默認范圍 default extent = None
generate_imshow_demo_grid(extents=[None])
通常,對于形狀(M, N)的數組,第一個索引沿垂直方向運行,第二個索引沿水平方向運行。像素中心位于整數位置,水平范圍為0到N'= N - 1
,垂直范圍為0到M'= M - 1
。origin確定如何在邊界框中填充邊框。
對于origin = 'lower'
:
[0, 0]
對應的是(左,下)[M', 0]
對應的是(左,上)[0, N']
對應的是(右,下)[M', N']
對應的是(右,上)
對于origin = 'upper'
將會反轉垂直軸的方向和填充:
[0, 0]
對應的是(左,上)[M', 0]
對應的是(左,下)[0, N']
對應的是(右,上)[M', N']
對應的是(右,下)
總之,[0, 0]
的位置和范圍受到origin的影響:
origin | [0, 0] 位置 | 范圍 |
---|---|---|
upper | 上左 | (-0.5, numcols-0.5, numrows-0.5, -0.5) |
lower | 下左 | (-0.5, numcols-0.5, -.05, numrows-0.5) |
origin的默認值由rcParams["image.origin"]
(默認值為’upper’)設置,默認為’upper’以匹配數學和計算機圖像索引約定中的矩陣索引約定。
2 顯式范圍
通過設置范圍,我們定義圖像區域的坐標。對基礎圖像數據進行插值/重采樣以填充該區域。
如果Axes設置為自動縮放,則Axes的視圖限制將設置為范圍匹配,從而確保(left, bottom)設置的坐標位于Axes的左下角。但是,這可能會反轉軸,因此它們不會在“自然”方向上增加:
extents = [(-0.5, 6.5, -0.5, 5.5),(-0.5, 6.5, 5.5, -0.5),(6.5, -0.5, -0.5, 5.5),(6.5, -0.5, 5.5, -0.5)]columns = generate_imshow_demo_grid(extents)
set_extent_None_text(columns['upper'][1])
set_extent_None_text(columns['lower'][0])
3 顯式確定范圍和Axes極限
如果我們通過顯式設置set_xlim/set_ylim來固定Axes極限,我們會強制Axes的一定大小和方向。這可以將圖像的“左-右”和“上-下”感覺與屏幕上的方向分離。
在下面的示例中,我們選擇了略大于范圍的極限(注意Axes內的白色區域)。
雖然我們保留了前面示例中的范圍,但坐標(0,0)現在顯式地放在左下角,值向上和向右增加(從查看者的角度來看)。我們可以看到:
- 坐標(左,下)錨定圖像,然后填充朝向數據空間中(右,上)點的框;
- 第一列始終最靠近“左”;
- 原點控制第一行是最接近“頂部”還是“底部”;
- 圖像可以沿任一方向反轉;
- 圖像的“左-右”和“自上-下”感覺可能與屏幕上的方向無關。