|
1 |
| -# 3.2 使用样式表自定义绘图 |
| 1 | +# 图像教程 |
2 | 2 |
|
3 |
| -> 原文:[Customizing plots with style sheets](http://matplotlib.org/users/style_sheets.html) |
| 3 | +> 原文:[Image tutorial](http://matplotlib.org/users/image_tutorial.html) |
4 | 4 |
|
5 | 5 | > 译者:[飞龙](https://github.com/)
|
6 | 6 |
|
7 | 7 | > 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)
|
8 | 8 |
|
9 |
| -`style`包为易于切换的绘图『样式』增加了支持,它们与`matplotlibrc`文件参数相同。 |
| 9 | +## 启动命令 |
10 | 10 |
|
11 |
| -有一些预定义样式由`matplotlib`提供。 例如,有一个名为『ggplot』的预定义样式,它模拟`ggplot`(R 的一种流行的绘图软件包)的美学。 为了使用此样式,只需添加: |
| 11 | +首先,让我们启动 IPython。 它是 Python 标准提示符的最好的改进,它与 Matplotlib 配合得相当不错。 在 shell 或 IPython Notebook 上都可以启动 IPython。 |
| 12 | + |
| 13 | +随着 IPython 启动,我们现在需要连接到 GUI 事件循环。 它告诉 IPython 在哪里(以及如何显示)绘图。 要连接到 GUI 循环,请在 IPython 提示符处执行`%matplotlib`魔法。 在 [IPython 的 GUI 事件循环文档](http://ipython.org/ipython-doc/2/interactive/reference.html#gui-event-loop-support)中有更多的细节。 |
| 14 | + |
| 15 | +如果使用 IPython Notebook,可以使用相同的命令,但人们通常以特定参数使用`%matplotlib`: |
| 16 | + |
| 17 | +``` |
| 18 | +In [1]: %matplotlib inline |
| 19 | +``` |
| 20 | + |
| 21 | +这将打开内联绘图,绘图图形将显示在笔记本中。 这对交互性有很重要的影响。 对于内联绘图,在单元格下方的单元格中输出绘图的命令不会影响绘图。 例如,从创建绘图的单元格下面的单元格更改颜色表是不可能的。 但是,对于其他后端,例如 qt4,它们会打开一个单独的窗口,那些创建绘图的单元格下方的单元格将改变绘图 - 它是一个内存中的活对象。 |
| 22 | + |
| 23 | +本教程将使用`matplotlib`的命令式绘图接口`pyplot`。 该接口维护全局状态,并且可用于简单快速地尝试各种绘图设置。 另一种是面向对象的接口,这也非常强大,一般更适合大型应用程序的开发。 如果你想了解面向对象接口,[使用上的常见问题](http://matplotlib.org/faq/usage_faq.html)是一个用于起步的不错的页面。 现在,让我们继续使用命令式方式: |
| 24 | + |
| 25 | +```py |
| 26 | +In [2]: import matplotlib.pyplot as plt |
| 27 | +In [3]: import matplotlib.image as mpimg |
| 28 | +In [4]: import numpy as np |
| 29 | +``` |
| 30 | + |
| 31 | +## 将图像数据导入到 NumPy 数组 |
| 32 | + |
| 33 | +加载图像数据由 Pillow 库提供支持。 本来,`matplotlib`只支持 PNG 图像。 如果本机读取失败,下面显示的命令会回退到 Pillow。 |
| 34 | + |
| 35 | +此示例中使用的图像是 PNG 文件,但是请记住你自己的数据的 Pillow 要求。 |
| 36 | + |
| 37 | +下面是我们要摆弄的图片: |
| 38 | + |
| 39 | + |
| 40 | + |
| 41 | +它是一个 24 位 RGB PNG 图像(每个 R,G,B 为 8 位)。 根据你获取数据的位置,你最有可能遇到的其他类型的图像是 RGBA 图像,拥有透明度或单通道灰度(亮度)的图像。 你可以右键单击它,选择`Save image as`(另存为)为本教程的剩余部分下载到你的计算机。 |
| 42 | + |
| 43 | +现在我们开始... |
| 44 | + |
| 45 | +```py |
| 46 | +In [5]: img=mpimg.imread('stinkbug.png') |
| 47 | +Out[5]: |
| 48 | +array([[[ 0.40784314, 0.40784314, 0.40784314], |
| 49 | + [ 0.40784314, 0.40784314, 0.40784314], |
| 50 | + [ 0.40784314, 0.40784314, 0.40784314], |
| 51 | + ..., |
| 52 | + [ 0.42745098, 0.42745098, 0.42745098], |
| 53 | + [ 0.42745098, 0.42745098, 0.42745098], |
| 54 | + [ 0.42745098, 0.42745098, 0.42745098]], |
| 55 | + |
| 56 | + ..., |
| 57 | + [[ 0.44313726, 0.44313726, 0.44313726], |
| 58 | + [ 0.4509804 , 0.4509804 , 0.4509804 ], |
| 59 | + [ 0.4509804 , 0.4509804 , 0.4509804 ], |
| 60 | + ..., |
| 61 | + [ 0.44705883, 0.44705883, 0.44705883], |
| 62 | + [ 0.44705883, 0.44705883, 0.44705883], |
| 63 | + [ 0.44313726, 0.44313726, 0.44313726]]], dtype=float32) |
| 64 | +``` |
| 65 | + |
| 66 | +注意这里的`dtype` - `float32`。 Matplotlib 已将每个通道的8位数据重新定标为 0.0 和 1.0 之间的浮点数。 作为旁注,Pillow 可以使用的唯一数据类型是`uint8`。 Matplotlib 绘图可以处理`float32`和`uint8`,但是对于除 PNG 之外的任何格式的图像,读取/写入仅限于`uint8`数据。 为什么是 8 位呢? 大多数显示器只能渲染每通道 8 位的颜色渐变。 为什么他们只能渲染每通道 8 位呢? 因为这会使所有人的眼睛可以看到。 更多信息请见(从摄影的角度):[Luminous Landscape 位深度教程](http://www.luminous-landscape.com/tutorials/bit-depth.shtml)。 |
| 67 | + |
| 68 | +每个内部列表表示一个像素。 这里,对于 RGB 图像,有 3 个值。 由于它是一个黑白图像,R,G 和 B 都是类似的。 RGBA(其中 A 是阿尔法或透明度)对于每个内部列表具有 4 个值,而且简单亮度图像仅具有一个值(因此仅是二维数组,而不是三维数组)。 对于 RGB 和 RGBA 图像,`matplotlib`支持`float32`和`uint8`数据类型。 对于灰度,`matplotlib`只支持`float32`。 如果你的数组数据不符合这些描述之一,则需要重新缩放它。 |
| 69 | + |
| 70 | +## 将 NumPy 数组绘制为图像 |
| 71 | + |
| 72 | +所以,你将数据保存在一个`numpy`数组(通过导入它,或生成它)。 让我们渲染它吧。 在 Matplotlib 中,这是使用`imshow()`函数执行的。 这里我们将抓取`plot`对象。 这个对象提供了一个简单的方法来从提示符处理绘图。 |
| 73 | + |
| 74 | +```py |
| 75 | +In [6]: imgplot = plt.imshow(img) |
| 76 | +``` |
| 77 | + |
| 78 | + |
| 79 | + |
| 80 | +你也可以绘制任何 NumPy 数组。 |
| 81 | + |
| 82 | +### 对图像绘图应用伪彩色方案 |
| 83 | + |
| 84 | +伪彩色可以是一个有用的工具,用于增强对比度和更易于可视化你的数据。 这在使用投影仪对你的数据进行演示时尤其有用 - 它们的对比度通常很差。 |
| 85 | + |
| 86 | +伪彩色仅与单通道,灰度,亮度图像相关。 我们目前有一个RGB图像。 由于R,G 和 B 都是相似的(见上面或你的数据),我们可以只选择一个通道的数据: |
12 | 87 |
|
13 | 88 | ```py
|
14 |
| ->>> import matplotlib.pyplot as plt |
15 |
| ->>> plt.style.use('ggplot') |
| 89 | +In [7]: lum_img = img[:,:,0] |
16 | 90 | ```
|
17 | 91 |
|
18 |
| -为了列出所有可用样式,使用: |
| 92 | +这是数组切片,更多信息请见[NumPy 教程](http://www.scipy.org/Tentative_NumPy_Tutorial)。 |
19 | 93 |
|
20 | 94 | ```py
|
21 |
| ->>> print(plt.style.available) |
| 95 | +In [8]: plt.imshow(lum_img) |
22 | 96 | ```
|
23 | 97 |
|
24 |
| -## 定义你自己的样式 |
| 98 | + |
25 | 99 |
|
26 |
| -你可以创建自定义样式,并通过以样式表的路径或 URL 调用`style.use`来使用它们。 或者,如果将`<style-name> mplstyle`文件添加到`mpl_configdir /stylelib`中,你可以通过调用`style.use(<style-name>)`重复使用自定义样式表。 默认情况下`mpl_configdir`应该是`~/.config/matplotlib`,但你可以使用`matplotlib.get_configdir()`检查你的位置,你可能需要创建这个目录。 请注意,如果样式具有相同的名称,`mpl_configdir/stylelib`中的自定义样式表将覆盖由`matplotlib`定义的样式表。 |
| 100 | +现在,亮度(2D,无颜色)图像应用了默认颜色表(也称为查找表,LUT)。 默认值称为`jet`。 有很多其他方案可以选择。 |
27 | 101 |
|
28 |
| -例如,你可能想要使用以下命令创建`mpl_configdir/stylelib/presentation.mplstyle`: |
| 102 | +```py |
| 103 | +In [9]: plt.imshow(lum_img, cmap="hot") |
| 104 | +``` |
| 105 | + |
| 106 | + |
| 107 | + |
| 108 | + |
| 109 | +请注意,你还可以使用`set_cmap()`方法更改现有绘图对象上的颜色: |
| 110 | + |
| 111 | +```py |
| 112 | +In [10]: imgplot = plt.imshow(lum_img) |
| 113 | +In [11]: imgplot.set_cmap('spectral') |
| 114 | +``` |
29 | 115 |
|
| 116 | + |
| 117 | + |
| 118 | +> 注 |
| 119 | +
|
| 120 | +> 但是,请记住,在带有内联后端的 IPython notebook 中,你不能对已经渲染的绘图进行更改。 如果你在一个单元格中创建了`imgplot`,你不能在以后的单元格中调用`set_cmap()`,并且改变前面的绘图。 请确保你在相同单元格中一起输入这些命令。`plt`命令不会更改先前单元格的绘图。 |
| 121 | +
|
| 122 | +有许多可选的其它颜色表,请见[颜色表的列表和图像](http://matplotlib.org/examples/color/colormaps_reference.html)。 |
| 123 | + |
| 124 | +### 颜色刻度参考 |
| 125 | + |
| 126 | +了解颜色代表什么值对我们很有帮助。 我们可以通过添加颜色条来做到这一点。 |
| 127 | + |
| 128 | +```py |
| 129 | +In [12]: imgplot = plt.imshow(lum_img) |
| 130 | +In [13]: plt.colorbar() |
30 | 131 | ```
|
31 |
| -axes.titlesize : 24 |
32 |
| -axes.labelsize : 20 |
33 |
| -lines.linewidth : 3 |
34 |
| -lines.markersize : 10 |
35 |
| -xtick.labelsize : 16 |
36 |
| -ytick.labelsize : 16 |
| 132 | + |
| 133 | + |
| 134 | + |
| 135 | +这会为你现有的图形添加一个颜色条。 如果你更改并切换到不同的颜色映射,则不会自动更改 - 你必须重新创建绘图,并再次添加颜色条。 |
| 136 | + |
| 137 | +### 检查特定数据范围 |
| 138 | + |
| 139 | +有时,你想要增强图像的对比度,或者扩大特定区域的对比度,同时牺牲变化不大,或者无所谓的颜色细节。 找到有趣区域的最好工具是直方图。 要创建我们的图像数据的直方图,我们使用`hist()`函数。 |
| 140 | + |
| 141 | +```py |
| 142 | +In [14]: plt.hist(lum_img.ravel(), bins=256, range=(0.0, 1.0), fc='k', ec='k') |
37 | 143 | ```
|
38 | 144 |
|
39 |
| -然后,当你想要将一个为纸张设计的地图迁移到演示文档中时,你可以添加: |
| 145 | + |
| 146 | + |
| 147 | +通常,图像的『有趣』部分在峰值附近,你可以通过剪切峰值上方和/或下方的区域获得额外的对比度。 在我们的直方图中,看起来最大值处没有太多有用的信息(图像中有很多不是白色的东西)。 让我们调整上限,以便我们有效地『放大』直方图的一部分。 我们通过将`clim`参数传递给`imshow`来实现。 你也可以通过对图像绘图对象调用`set_clim()`方法来做到这一点,但要确保你在使用 IPython Notebook 的时候,和`plot`命令在相同的单元格中执行 - 它不会改变之前单元格的图。 |
40 | 148 |
|
41 | 149 | ```py
|
42 |
| ->>> import matplotlib.pyplot as plt |
43 |
| ->>> plt.style.use('presentation') |
| 150 | +In [15]: imgplot = plt.imshow(lum_img, clim=(0.0, 0.7)) |
44 | 151 | ```
|
45 | 152 |
|
46 |
| -## 组合样式 |
| 153 | + |
| 154 | + |
| 155 | +### 数组插值方案 |
| 156 | + |
| 157 | +插值根据不同的数学方案计算像素『应有』的颜色或值。 发生这种情况的一个常见的场景是调整图像的大小。 像素的数量会发生变化,但你想要相同的信息。 由于像素是离散的,因此存在缺失的空间。 插值就是填补这个空间的方式。 这就是当你放大图像时,你的图像有时会出来看起来像素化的原因。 当原始图像和扩展图像之间的差异较大时,效果更加明显。 让我们加载我们的图像并缩小它。 我们实际上正在丢弃像素,只保留少数几个像素。 现在,当我们绘制它时,数据被放大为你屏幕的大小。 由于旧的像素不再存在,计算机必须绘制像素来填充那个空间。 |
47 | 158 |
|
48 |
| -样式表为组合在一起而设计。 因此,你可以拥有一个自定义颜色的样式表和一个单独的样式表,用于更改演示文档的元素大小。 这些样式可以通过传递样式列表轻松组合: |
| 159 | +我们将使用用来加载图像的 Pillow 库来调整图像大小。 |
49 | 160 |
|
50 | 161 | ```py
|
51 |
| ->>> import matplotlib.pyplot as plt |
52 |
| ->>> plt.style.use(['dark_background', 'presentation']) |
| 162 | +In [16]: from PIL import Image |
| 163 | +In [17]: img = Image.open('../_static/stinkbug.png') |
| 164 | +In [18]: img.thumbnail((64, 64), Image.ANTIALIAS) # resizes image in-place |
| 165 | +In [19]: imgplot = plt.imshow(img) |
53 | 166 | ```
|
54 | 167 |
|
55 |
| -请注意,右侧的样式将覆盖已经由左侧样式定义的值。 |
| 168 | + |
56 | 169 |
|
57 |
| -## 临时样式 |
| 170 | +这里我们使用默认插值,双线性,因为我们没有向`imshow()`提供任何插值参数。 |
58 | 171 |
|
59 |
| -如果只想对特定的代码块使用样式,但不想更改全局样式,那么样式包提供了一个上下文管理器,用于将更改限制于特定范围。 要隔离你的样式更改,你可以编写以下内容: |
| 172 | +让我们试试一些其它的东西: |
| 173 | + |
| 174 | +最邻近 |
| 175 | + |
| 176 | +```py |
| 177 | +In [20]: imgplot = plt.imshow(img, interpolation="nearest") |
| 178 | +``` |
| 179 | + |
| 180 | + |
| 181 | + |
| 182 | +双立方 |
60 | 183 |
|
61 | 184 | ```py
|
62 |
| ->>> import numpy as np |
63 |
| ->>> import matplotlib.pyplot as plt |
64 |
| ->>> |
65 |
| ->>> with plt.style.context(('dark_background')): |
66 |
| ->>> plt.plot(np.sin(np.linspace(0, 2 * np.pi)), 'r-o') |
67 |
| ->>> |
68 |
| ->>> # Some plotting code with the default style |
69 |
| ->>> |
70 |
| ->>> plt.show() |
| 185 | +In [21]: imgplot = plt.imshow(img, interpolation="bicubic") |
71 | 186 | ```
|
| 187 | + |
| 188 | + |
| 189 | + |
| 190 | +双立方插值通常用于放大照片 - 人们倾向于模糊而不是过度像素化。 |
0 commit comments