现在可以导入 matplotlib 并显示一些数据。您将加载 scikit-image 库 data 模块中包含的示例数据:
import matplotlib.pyplot as plt
from skimage import data
astronaut = data.astronaut()
ihc = data.immunohistochemistry()
hubble = data.hubble_deep_field()
# Initialize the subplot panels side by side
fig, ax = plt.subplots(nrows=1, ncols=3)
# Show an image in each subplot
ax[0].imshow(astronaut)
ax[0].set_title('Natural image')
ax[1].imshow(ihc)
ax[1].set_title('Microscopy image')
ax[2].imshow(hubble)
ax[2].set_title('Telescope image');技术支持
我们将下载 Buchel 和 Friston 于 1997 年发表的 Cortical Interactions Evaluated with Structural Equation Modelling and fMRI 一文中描述的数据集。首先,我们创建一个临时目录以下载数据。完成分析后务必删除它!如果您想保留该数据集以备后用,请将 d 更改为您选择的更持久的目录位置。
import tempfile
# Create a temporary directory
d = tempfile.mkdtemp()技术支持
现在,来下载数据:
import os
# Return the tail of the path
os.path.basename('http://google.com/attention.zip')技术支持
from urllib.request import urlretrieve
# Define URL
url ='http://www.fil.ion.ucl.ac.uk/spm/download/data/attention/attention.zip'
# Retrieve the data
fn, info =urlretrieve(url, os.path.join(d,'attention.zip'))技术支持
并将其从 zip 文件解压到我们的临时目录:
import zipfile
# Extract the contents into the temporary directory we created earlier
zipfile.ZipFile(fn).extractall(path=d)技术支持
如果您查看文件的实际内容,会发现一堆“.hdr”和“.img”文件。
# List first 10 files
[f.filename for f in zipfile.ZipFile(fn).filelist[:10]]技术支持
# Read the image
struct = nibabel.load(os.path.join(d,'attention/structural/nsM00587_0002.hdr'))
# Get a plain NumPy array, without all the metadata
struct_arr = struct.get_data()技术支持
提示:如果您想直接继续绘制 MRI 数据,请执行以下代码:
from skimage import io
struct_arr = io.imread("https://s3.amazonaws.com/assets.datacamp.com/blog_assets/attention-mri.tif")技术支持
大多数人都熟悉由普通相机拍摄的图像数据(学术文献中常称为“自然图像”),也熟悉由显微镜或望远镜等专业仪器采集的图像。在 Python 中处理图像时,最常见的显示方式是使用 Matplotlib(Python 最流行的绘图库)的 imshow 函数。
在本教程中,我们将向您展示如何扩展该函数以显示三维体数据,您可以将其视为一叠图像。它们共同描述一个三维结构。例如,磁共振成像(MRI)和计算机断层扫描(CT)测量人体内部的三维结构;X 射线显微断层扫描测量玻璃或金属合金等材料内部的三维结构;光片显微镜测量生物组织内的荧光颗粒。
我们将演示如何下载一个 MRI 数据集,并使用
matplotlib显示其切片。您将学习如何:nibabel库获取数据,该库提供 NIfTI 文件格式的读取器。若您想跳过此步骤直接开始绘图,本教程也将展示如何使用 scikit-image 获取数据。但首先,让我们回顾一些基础:如何使用 Matplotlib 的
imshow显示图像。如果您在 Jupyter Notebook 中工作,可以先启用 matplotlib 交互模式:
现在可以导入
matplotlib并显示一些数据。您将加载 scikit-image 库 data 模块中包含的示例数据:注意:当您在交互式笔记本模式下运行 matplotlib 时,打开的图形会一直保持为唯一的活动图形,直到您通过图形右上角的电源符号将其禁用。在继续下一幅图之前,请务必先执行该操作。
这些图像称为二维(2D)图像,因为它们沿两个维度展开:x 和 y,或用 NumPy 的惯用语,行和列(r 与 c)。
有些图像是三维(3D)的,即具有额外的深度维度(z,或称为平面)。这包括磁共振成像(MRI)和串行切片透射电子显微镜(ssTEM),其中样本被像萨拉米香肠一样薄切,每片分别成像。
要在 matplotlib 中查看此类图像,我们必须选择一个切片,仅显示该切片。让我们在网上一些可自由获取的 MRI 数据上试试。
插曲:获取数据
我们将下载 Buchel 和 Friston 于 1997 年发表的 Cortical Interactions Evaluated with Structural Equation Modelling and fMRI 一文中描述的数据集。首先,我们创建一个临时目录以下载数据。完成分析后务必删除它!如果您想保留该数据集以备后用,请将
d更改为您选择的更持久的目录位置。现在,来下载数据:
并将其从
zip文件解压到我们的临时目录:如果您查看文件的实际内容,会发现一堆“.hdr”和“.img”文件。
这些采用 NIfTI 文件格式,我们需要一个读取器。幸运的是,优秀的
nibabel库提供了这样的读取器。请务必使用conda install -c conda-forge nibabel或pip install nibabel安装它,然后:现在,我们终于可以读取图像,并使用
.get_data()方法获取用于查看的 NumPy 数组:提示:如果您想直接继续绘制 MRI 数据,请执行以下代码:
回到绘图
现在让我们看看该数组中的一个切片:
哇!看起来挺“挤”的!这是因为许多 MRI 在垂直轴上的分辨率与水平方向不同。我们可以通过向
imshow函数传递aspect参数来修复:不过,为了更省事,我们将直接转置数据,只查看不需要这种调整的水平切片。
很漂亮!当然,如果要查看其他切片,或沿不同轴的切片,我们需要再次调用
imshow:这些调用很快就会变得相当繁琐。很长一段时间里,我会使用 Python 之外的工具查看三维体数据,例如 ITK-SNAP。但事实证明,为 matplotlib 查看器添加三维“滚动”功能非常容易!这使我们可以在 Python 内部探索三维数据,最大限度减少在数据探索与数据分析之间切换的需要。
关键在于使用
matplotlib的事件处理 API,它允许我们为特定的按键或鼠标点击定义在绘图上执行的操作——包括更改绘图数据!在我们的例子中,让我们将键盘上的 J 和 K 键绑定为“上一张切片”和“下一张切片”:
相当简单!当然,我们需要想办法实际实现这些操作,并且要告诉图形应使用
process_key函数来处理键盘按键!后者很简单:只需使用图形画布方法mpl_connect:您可以在此处找到
mpl_connect的完整文档,包括可以绑定的其他事件类型(如鼠标点击)。我稍加探索后发现,
imshow返回一个AxesImage对象,它“位于”进行所有绘制的 matplotlibAxes对象内部的.images属性中。该对象提供了方便的set_array方法,可替换正在显示的图像数据!因此,我们只需:Axes对象的额外运行时属性。next_slice和previous_slice函数,修改索引并使用set_array设置三维体对应的切片。draw方法以新数据重绘图形。试试看!
能用!不错!不过,如果您在本地试试,会注意到向上滚动(按 K)也会把图的水平比例压缩。嗯?(只有当鼠标位于图像上方时才会发生。)
原因是向 Matplotlib 添加事件处理程序时,它们只是被层层叠加。在这个例子中,K 是一个内置快捷键,用于将 x 轴改为对数刻度。如果我们想专用 K,就必须将其从
matplotlib的默认按键映射中移除。这些映射以列表形式存放在plt.rcParams字典中,它是matplotlib的系统级默认设置库:按下列表中的任意按键(即
<key1>或<key2>)都会触发执行<command>。因此,我们需要编写一个辅助函数,从该字典中任何位置移除我们想要占用的按键。(该函数在
matplotlib中尚不存在,但大概会是个受欢迎的贡献!)一个功能完整的切片查看器
好,让我们重写函数以使用这个新工具:
现在,我们应该可以在 MRI 体数据中查看所有切片,而不会再受到默认按键映射的干扰了!
这种方法的一个优点是它适用于任何 matplotlib 后端!因此,即使您在 IPython 终端控制台中尝试,也能获得与浏览器中相同的交互体验!对嵌入 matplotlib 图的 Qt 或 Tkinter 应用同样如此。这个简单工具因此使您能够围绕 matplotlib 的可视化能力构建更复杂的应用程序。
临走之前
别忘了善后,删除临时目录(如果您创建了的话):
总结
恭喜!一路走来不易,但您已经完成了本次 Matplotlib 教程!
敬请关注本系列的第二篇文章,您将继续学习如何缩放子图、使用十字准线显示每个图的切片位置,以及添加鼠标交互。
查看 DataCamp 的 Matplotlib 教程:Python 绘图。
如果您想进一步了解 Python 中的数据可视化,欢迎学习 DataCamp 的 Introduction to Data Visualization in Python 课程。