提交 8af46deb 编写于 作者: W wizardforcel

8.6-8.11

上级 659a4e53
# 8.10 自定义颜色条
> 原文:[Customizing Colorbars](https://nbviewer.jupyter.org/github/donnemartin/data-science-ipython-notebooks/blob/master/matplotlib/04.07-Customizing-Colorbars.ipynb)
>
> 译者:[飞龙](https://github.com/wizardforcel)
>
> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)
>
> 本节是[《Python 数据科学手册》](https://github.com/jakevdp/PythonDataScienceHandbook)(Python Data Science Handbook)的摘录。
绘图图例标识离散点的离散标签。对于基于点,线条或区域颜色的连续标签,带标签的颜色条可能是一个很好的工具。在 Matplotlib 中,颜色条是一个单独的轴域,可以为绘图中的颜色含义提供见解。原书是黑白打印的,但是在线版本是彩色的,你可以在这里看到全彩的图形。我们首先设置笔记本来绘图,并导入我们将使用的函数:
```py
import matplotlib.pyplot as plt
plt.style.use('classic')
%matplotlib inline
import numpy as np
```
我们在本节中多次看到,可以使用``plt.colorbar``函数创建最简单的颜色条:
```py
x = np.linspace(0, 10, 1000)
I = np.sin(x) * np.cos(x[:, np.newaxis])
plt.imshow(I)
plt.colorbar();
```
![png](../img/8-10-1.png)
我们现在将讨论一些想法,自定义这些颜色条,并在各种情况下有效地使用它们。
## 自定义颜色条
可以使用创建可视化的绘图函数的``cmap``参数指定颜色条:
```py
plt.imshow(I, cmap='gray');
```
![png](../img/8-10-2.png)
所有可用的颜色表都在``plt.cm``命名空间中;IPython 的 TAB 补全,将为你提供内置选项的完整列表:
```ipython
plt.cm.<TAB>
```
但是能够选择颜色表只是第一步:更重要的是如何在选项中做决策!选择结果比你最初预期的要微妙得多。
### 选择颜色表
可视化中的颜色选择的完全处理,超出了本书的范围,但是为了阅读这个主题和其他内容,请参阅文章[“更好的绘图的十个简单的规则”](http://journals.plos.org/ploscompbiol/article?id=10.1371/journal.pcbi.1003833)。Matplotlib 的在线文档还有一个关于颜色表选择的[有趣讨论](http://Matplotlib.org/1.4.1/users/colormaps.html)
一般来讲,你应该了解三种不同类型的颜色表:
- 顺序颜色表:它们由连续的颜色序列组成(例如,``binary````viridis``)。
- 发散颜色表:这些通常包含两种不同的颜色,显示相对均值的正偏差和负偏差(例如,``RdBu````PuOr``)。
- 定性颜色表:这些混合颜色没有特定的顺序(例如,``rainbow````jet``)。
``jet``颜色表是 2.0 版之前 Matplotlib 中的默认值,是定性颜色表的一个示例。它的默认状态非常不幸,因为对于表示定量数据来讲,定性映射往往是不良选择。问题之一是,定性映射通常在尺度增加时不显示任何均匀的亮度变化。
我们可以通过将``jet``颜色表转换成黑白来看到这一点:
```py
from matplotlib.colors import LinearSegmentedColormap
def grayscale_cmap(cmap):
"""返回给定颜色表的灰度版本"""
cmap = plt.cm.get_cmap(cmap)
colors = cmap(np.arange(cmap.N))
# 将 RGBA 转换为感知灰度亮度
# cf. http://alienryderflex.com/hsp.html
RGB_weight = [0.299, 0.587, 0.114]
luminance = np.sqrt(np.dot(colors[:, :3] ** 2, RGB_weight))
colors[:, :3] = luminance[:, np.newaxis]
return LinearSegmentedColormap.from_list(cmap.name + "_gray", colors, cmap.N)
def view_colormap(cmap):
"""使用颜色表的灰度等价物来绘制它"""
cmap = plt.cm.get_cmap(cmap)
colors = cmap(np.arange(cmap.N))
cmap = grayscale_cmap(cmap)
grayscale = cmap(np.arange(cmap.N))
fig, ax = plt.subplots(2, figsize=(6, 2),
subplot_kw=dict(xticks=[], yticks=[]))
ax[0].imshow([colors], extent=[0, 10, 0, 1])
ax[1].imshow([grayscale], extent=[0, 10, 0, 1])
view_colormap('jet')
```
![png](../img/8-10-3.png)
注意灰度图像中的明亮条纹。即使是全彩色,这种不均匀的亮度意味着,眼睛会被吸引到颜色范围的某些部分,这可能会强调数据集的不重要部分。最好使用例如``viridis``(Matplotlib 2.0 的默认值)的颜色表,它专门为在整个范围内具有均匀的亮度变化而构建。因此,它不仅可以很好地适应我们的色彩感知,而且可以很好地转换为灰度打印:
```py
view_colormap('viridis')
```
![png](../img/8-10-4.png)
如果你喜欢彩虹图案,连续数据的另一个良好选择是``cubehelix``颜色表:
```py
view_colormap('cubehelix')
```
![png](../img/8-10-5.png)
对于其他情况,例如显示某些均值的正偏差和负偏差,诸如`RdBu`(Red-Blue)的双色颜色表可能是有用的。但是,你会在下图中看到,重要的是要注意,在转换为灰度时,正负信息将会丢失!
```py
view_colormap('RdBu')
```
![png](../img/8-10-6.png)
当我们继续时,我们将看到使用其中一些颜色表的示例。
Matplotlib 中有大量的颜色表;要查看它们的列表,可以使用 IPython 来探索``plt.cm``子模块。对于在 Python 中使用颜色的更加合乎正道的途径,你可以参考 Seaborn 库中的工具和文档(参见“使用 Seaborn 进行可视化”)。
### 颜色限制和扩展
Matplotlib 允许定制大范围的颜色条。颜色条本身只是``plt.Axes``的一个实例,所以我们学到的所有轴域和刻度的格式化技巧都适用。颜色条有一些有趣的灵活性:例如,我们可以缩小颜色限制,并通过设置``extend``属性,在顶部和底部用三角形箭头指示越界值。这可能会派上用场,例如,如果显示受噪声影响的图像:
```py
# 为 1% 的图像像素生成噪声
speckles = (np.random.random(I.shape) < 0.01)
I[speckles] = np.random.normal(0, 3, np.count_nonzero(speckles))
plt.figure(figsize=(10, 3.5))
plt.subplot(1, 2, 1)
plt.imshow(I, cmap='RdBu')
plt.colorbar()
plt.subplot(1, 2, 2)
plt.imshow(I, cmap='RdBu')
plt.colorbar(extend='both')
plt.clim(-1, 1);
```
![png](../img/8-10-7.png)
请注意,在左侧面板中,默认颜色限制会响应噪声像素,并且噪声范围会完全消除我们感兴趣的模式。在右侧面板中,我们手动设置颜色限制,并添加扩展来标识高于或低于这些限制的值。结果是对我们的数据更加有用的可视化。
### 离散颜色条
默认情况下,颜色表是连续的,但有时你想表示离散值。最简单的方法是使用``plt.cm.get_cmap()``函数,并传递合适的颜色表的名称以及所需的桶数:
```py
plt.imshow(I, cmap=plt.cm.get_cmap('Blues', 6))
plt.colorbar()
plt.clim(-1, 1);
```
![png](../img/8-10-8.png)
颜色表的离散版本可以像任何其他颜色表一样使用。
## 示例:手写数字
对于这可能有用的示例,让我们看一些手写数字数据的有趣可视化。
这些数据包含在 Scikit-Learn 中,包含近 2,000 张`8x8`的缩略图,显示各种手写数字。
现在,让我们首先下载数字数据并使用``plt.imshow()``可视化几个示例图像:
```py
# 加载数字 0~5 的图像
# 可视化它们中的几个
from sklearn.datasets import load_digits
digits = load_digits(n_class=6)
fig, ax = plt.subplots(8, 8, figsize=(6, 6))
for i, axi in enumerate(ax.flat):
axi.imshow(digits.images[i], cmap='binary')
axi.set(xticks=[], yticks=[])
```
![png](../img/8-10-9.png)
因为每个数字由其 64 个像素的亮度定义,我们可以将每个数字视为位于 64 维空间中的点:每个维度代表一个像素的亮度。但是在这种高维空间中可视化关系可能非常困难。解决这个问题的一种方法是使用降维技术,例如流形学习,来减少数据的维度,同时保持感兴趣的关系。降维是无监督机器学习的一个例子,我们将在“什么是机器学习?”中更详细地讨论它。
推迟对这些细节的讨论,让我们看一下这个数字数据的二维流形学习投影(详见“深入分析:流形学习”):
```py
# 使用 IsoMap 将数字投影到二维
from sklearn.manifold import Isomap
iso = Isomap(n_components=2)
projection = iso.fit_transform(digits.data)
```
我们将使用我们的离散颜色表来查看结果,设置``ticks````clim``来改善所得颜色条的美感:
```py
# 绘制结果
plt.scatter(projection[:, 0], projection[:, 1], lw=0.1,
c=digits.target, cmap=plt.cm.get_cmap('cubehelix', 6))
plt.colorbar(ticks=range(6), label='digit value')
plt.clim(-0.5, 5.5)
```
![png](../img/8-10-10.png)
该投影还为我们提供了一些数据集内部关系的有趣见解:例如,5 和 3 的范围在此投影中几乎重叠,表明一些手写的五和三难以区分,因此更容易由自动分类算法混淆。其他值,如 0 和 1,更加分散,因此更不容易混淆。这个观察结果与我们的直觉一致,因为 5 和 3 看起来比 0 和 1 更相似。
我们将在第 5 章中返回流形学习和数字分类。
\ No newline at end of file
# 8.11 多个子图
> 原文:[Multiple Subplots](https://nbviewer.jupyter.org/github/donnemartin/data-science-ipython-notebooks/blob/master/matplotlib/04.08-Multiple-Subplots.ipynb)
>
> 译者:[飞龙](https://github.com/wizardforcel)
>
> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)
>
> 本节是[《Python 数据科学手册》](https://github.com/jakevdp/PythonDataScienceHandbook)(Python Data Science Handbook)的摘录。
有时,并排比较不同的数据视图会很有帮助。为此,Matplotlib 具有子图的概念:可以在单个图形中一起存在的较小轴域分组。这些子图可能是插图,绘图网格或其他更复杂的布局。在本节中,我们将探讨在 Matplotlib 中创建子图的四个例程。
```py
%matplotlib inline
import matplotlib.pyplot as plt
plt.style.use('seaborn-white')
import numpy as np
```
## ``plt.axes``:手动创建子图
创建轴域的最基本方法是使用``plt.axes``函数。正如我们之前看到的,默认情况下,这会创建一个填充整个图形的标准轴域对象。``plt.axes``也有一个可选参数,它是图坐标系中四个数字的列表。这些数字代表图形坐标系中的“左,底,宽,高”``,其范围从图的左下角的 0 到图的右上角的 1。
例如,我们可以通过将`x`和`y`位置设置为 0.65(也就是说,从图形宽度的 65% 和高度的 65% 开始),`x`和`y`范围为 0.2(即轴域的大小是图形宽度的 20% 和高度的 20%),在另一个轴域的右上角创建一个插入的轴域:
```py
ax1 = plt.axes() # 标准轴域
ax2 = plt.axes([0.65, 0.65, 0.2, 0.2])
```
![png](../img/8-11-1.png)
在面向对象的接口中,这个命令的等价物是``fig.add_axes()``。 让我们用它来创建两个垂直堆叠的轴:
```py
fig = plt.figure()
ax1 = fig.add_axes([0.1, 0.5, 0.8, 0.4],
xticklabels=[], ylim=(-1.2, 1.2))
ax2 = fig.add_axes([0.1, 0.1, 0.8, 0.4],
ylim=(-1.2, 1.2))
x = np.linspace(0, 10)
ax1.plot(np.sin(x))
ax2.plot(np.cos(x));
```
![png](../img/8-11-2.png)
我们现在有两个刚刚接触的轴域(顶部没有刻度标签):上面板的底部(位置为 0.5)匹配下面板的顶部(位置为 0.1 + 0.4)。
## ``plt.subplot``:子图的简单网格
子图的对齐的列或行是一个常见的需求,Matplotlib 有几个便利例程,使它们易于创建。其中最低级别是``plt.subplot()``,它在网格中创建一个子图。如你所见,此命令接受三个整数参数 - 行数,列数和要在此图案中创建的绘图的索引,从左上角到右下角:
```py
for i in range(1, 7):
plt.subplot(2, 3, i)
plt.text(0.5, 0.5, str((2, 3, i)),
fontsize=18, ha='center')
```
![png](../img/8-11-3.png)
命令``plt.subplots_adjust``可用于调整这些图之间的间距。下面的代码使用等效的面向对象命令``fig.add_subplot()``:
```py
fig = plt.figure()
fig.subplots_adjust(hspace=0.4, wspace=0.4)
for i in range(1, 7):
ax = fig.add_subplot(2, 3, i)
ax.text(0.5, 0.5, str((2, 3, i)),
fontsize=18, ha='center')
```
![png](../img/8-11-4.png)
我们使用了``plt.subplots_adjust``的``hspace``和``wspace``参数,它们沿图的高度和宽度指定间距,以子图大小为单位(这里,间距是子图宽度和高度的 40%。
## ``plt.subplots``:一次创建整个网格
在创建大型子图网格时,刚才描述的方法会变得相当繁琐,特别是如果你想在内部绘图上隐藏`x`轴和`y`轴标签。为此,``plt.subplots()``是更容易使用的工具(注意``subplots``末尾的``s``)。 该函数不创建单个子图,而是在一行中创建完整的子图网格,并在 NumPy 数组中返回它们。参数是行数和列数,以及可选关键字``sharex``和``sharey``,它们允许你指定不同轴之间的关系。
在这里,我们将创建`2x3`子图的网格,其中同一行中的所有轴域共享其`y`轴刻度,并且同一列中的所有轴域共享其`x`轴刻度:
```py
fig, ax = plt.subplots(2, 3, sharex='col', sharey='row')
```
![png](../img/8-11-5.png)
请注意,通过指定``sharex``和``sharey``,我们会自动删除网格上的内部标签,来使绘图更清晰。生成的轴域网格实例在 NumPy 数组中返回,允许使用标准数组索引表示法,方便地指定所需的轴域:
```py
# ax 是二维数组,由 [row, col] 索引
for i in range(2):
for j in range(3):
ax[i, j].text(0.5, 0.5, str((i, j)),
fontsize=18, ha='center')
fig
```
![png](../img/8-11-6.png)
与``plt.subplot()``相比,``plt.subplots()``与 Python 传统的基于 0 的索引更加一致。
## ``plt.GridSpec``:更加复杂的排列
为了超越常规网格,转向跨越多行和列的子图,``plt.GridSpec()``是最好的工具。
``plt.GridSpec()``对象本身不会创建一个图;它只是一个方便的接口,可以通过``plt.subplot()``命令识别。例如,具有指定宽度和高度间距的,两行和三列网格的`gridspec`如下所示:
```py
grid = plt.GridSpec(2, 3, wspace=0.4, hspace=0.3)
```
从这里我们可以使用熟悉的 Python 切片语法来指定子图位置和范围:
```py
plt.subplot(grid[0, 0])
plt.subplot(grid[0, 1:])
plt.subplot(grid[1, :2])
plt.subplot(grid[1, 2]);
```
![png](../img/8-11-7.png)
这种类型的灵活网格对齐具有广泛的用途。我最经常在创建多轴域直方图时使用它,如下图所示:
```py
# 创建一些正态分布的数据
mean = [0, 0]
cov = [[1, 1], [1, 2]]
x, y = np.random.multivariate_normal(mean, cov, 3000).T
# 使用 gridspec 建立轴域
fig = plt.figure(figsize=(6, 6))
grid = plt.GridSpec(4, 4, hspace=0.2, wspace=0.2)
main_ax = fig.add_subplot(grid[:-1, 1:])
y_hist = fig.add_subplot(grid[:-1, 0], xticklabels=[], sharey=main_ax)
x_hist = fig.add_subplot(grid[-1, 1:], yticklabels=[], sharex=main_ax)
# 主要轴域上的散点图
main_ax.plot(x, y, 'ok', markersize=3, alpha=0.2)
# 附加轴域上的直方图
x_hist.hist(x, 40, histtype='stepfilled',
orientation='vertical', color='gray')
x_hist.invert_yaxis()
y_hist.hist(y, 40, histtype='stepfilled',
orientation='horizontal', color='gray')
y_hist.invert_xaxis()
```
![png](../img/8-11-8.png)
这种类型的分布与其外边距一起绘制,这是很常见的,它在 Seaborn 包中有自己的绘图 API; 详细信息请参阅“使用 Seaborn 进行可视化”。
# 8.6 可视化误差
> 原文:[Visualizing Errors](https://nbviewer.jupyter.org/github/donnemartin/data-science-ipython-notebooks/blob/master/matplotlib/04.03-Errorbars.ipynb)
>
> 译者:[飞龙](https://github.com/wizardforcel)
>
> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)
>
> 本节是[《Python 数据科学手册》](https://github.com/jakevdp/PythonDataScienceHandbook)(Python Data Science Handbook)的摘录。
对于任何科学测量,误差的准确计算几乎与数字本身的准确报告一样重要,甚至更重要。例如,假设我正在使用一些天体物理观测来估计哈勃常数,即宇宙膨胀率的局部测量值。我知道目前的文献显示,它是大约`71 (km/s)/Mpc`,我用我的方法测得的值为`74 (km/s)/Mpc`。这些值是否一致? 鉴于此信息,唯一正确的答案是:没有办法知道。
假设我用报告的不确定性来扩展这些信息:目前的文献显示它是`71 ± 2.5 (km/s)/Mpc`,我的方法测得的值为`74 ± 5 (km/s)/Mpc`。现在值是否一致? 这是一个可以定量回答的问题。
在数据和结果的可视化中,有效地显示这些误差,可以使图表传达更完整的信息。
## 基本的误差栏
可以使用单个 Matplotlib 函数调用,创建基本误差栏:
```py
%matplotlib inline
import matplotlib.pyplot as plt
plt.style.use('seaborn-whitegrid')
import numpy as np
x = np.linspace(0, 10, 50)
dy = 0.8
y = np.sin(x) + dy * np.random.randn(50)
plt.errorbar(x, y, yerr=dy, fmt='.k');
```
![png](../img/8-6-1.png)
这里``fmt``是控制线和点外观的格式代码,与``plt.plot``中使用的简写语法相同,在“简单的折线图”和“简单的散点图”中概述。
除了这些基本选项之外,``errorbar``函数还有许多选项可以微调输出。使用这些附加选项,你可以轻松自定义误差栏绘图的美感。我经常发现它有用,特别是在拥挤的绘图中,使误差栏比点本身更浅:
```py
plt.errorbar(x, y, yerr=dy, fmt='o', color='black',
ecolor='lightgray', elinewidth=3, capsize=0);
```
![png](../img/8-6-2.png)
除了这些选项,你还可以指定水平误差栏(``xerr``),单侧误差栏和许多其他变体。对于可用选项的更多信息,请参阅``plt.errorbar``的文档字符串。
## 连续误差
在某些情况下,希望在连续数量上显示误差栏。虽然 Matplotlib 没有为这种类型的应用内置便利例程,但是将`plt.plot``plt.fill_between`之类的原语组合起来来获得有用的结果,是相对容易的。
在这里,我们将使用 Scikit-Learn API 执行简单的高斯过程回归(详细信息,请参阅“Scikit-Learn 简介”)。这是一种方法,使用不确定性的连续测量,将非常灵活的非参数函数拟合到数据。我们现在不会深入研究高斯过程回归的细节,而是专注于如何可视化这种连续误差测量:
```py
from sklearn.gaussian_process import GaussianProcess
# 定义模型并绘制一些数据
model = lambda x: x * np.sin(x)
xdata = np.array([1, 3, 5, 6, 8])
ydata = model(xdata)
# 拟合高斯过程
gp = GaussianProcess(corr='cubic', theta0=1e-2, thetaL=1e-4, thetaU=1E-1,
random_start=100)
gp.fit(xdata[:, np.newaxis], ydata)
xfit = np.linspace(0, 10, 1000)
yfit, MSE = gp.predict(xfit[:, np.newaxis], eval_MSE=True)
dyfit = 2 * np.sqrt(MSE) # 2*sigma ~ 95% confidence region
```
我们现在有``xfit````yfit````dyfit``,它们对数据的连续拟合进行抽样。我们可以将这些传递给上面的``plt.errorbar``函数,但是我们真的不想绘制 1000 个点和 1000 个误差栏。相反,我们可以使用浅色的``plt.fill_between``函数来显示这个连续误差:
```py
# 可视化结果
plt.plot(xdata, ydata, 'or')
plt.plot(xfit, yfit, '-', color='gray')
plt.fill_between(xfit, yfit - dyfit, yfit + dyfit,
color='gray', alpha=0.2)
plt.xlim(0, 10);
```
![png](../img/8-6-3.png)
注意我们在这里使用``fill_between``函数做了什么:我们传递一个`x`值,然后是`y`下界,然后是`y`上面,结果就是之间的区域被填充了。
得到的图形可以用于非常直观地了解高斯过程回归算法正在做什么:在测量数据点附近的区域中,模型受到强烈约束,这反映在较小的模型误差中。在远离测量数据点的区域中,模型不受强烈约束,并且模型误差增加。
对于``plt.fill_between()``(以及密切相关的``plt.fill()``函数)中,可用选项的更多信息,请参阅函数的文档字符串或 Matplotlib 文档。
最后,如果这和你的品味相比,看起来有点太低了,请参考“可视化与 Seaborn”,其中我们讨论了 Seaborn 包,它有更简化的 API,用于可视化这种类型 的连续误差栏。
\ No newline at end of file
# 8.7 密度和等高线图
> 原文:[Density and Contour Plots](https://nbviewer.jupyter.org/github/donnemartin/data-science-ipython-notebooks/blob/master/matplotlib/04.04-Density-and-Contour-Plots.ipynb)
>
> 译者:[飞龙](https://github.com/wizardforcel)
>
> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)
>
> 本节是[《Python 数据科学手册》](https://github.com/jakevdp/PythonDataScienceHandbook)(Python Data Science Handbook)的摘录。
有时,使用等高线或颜色编码的区域,在二维中显示三维数据是有用的。有三个 Matplotlib 函数可以帮助完成这个任务:`plt.contour``用于等高线图,``plt.contourf``用于填充的等高线图,``plt.imshow``用于显示图像。本节介绍使用这些的几个示例。 我们首先设置笔记本来绘图,以及导入我们将使用的函数:
```py
%matplotlib inline
import matplotlib.pyplot as plt
plt.style.use('seaborn-white')
import numpy as np
```
## 可视化三维函数
我们首先使用`z = f(x, y)`函数演示等高线图,为`f`使用以下特定选项(当我们将它用作数组广播的动机示例时,我们之前在“数组计算:广播”中看到过它们):
```py
def f(x, y):
return np.sin(x) ** 10 + np.cos(10 + y * x) * np.cos(x)
```
可以使用``plt.contour``函数创建等高线图。它需要三个参数:`x`值的网格,`y`值的网格和`z`值的网格。`x`和`y`值表示图上的位置,`z`值将由等高线水平表示。也许准备这样的数据最直接的方法是使用``np.meshgrid``函数,它从一维数组构建二维网格:
```py
x = np.linspace(0, 5, 50)
y = np.linspace(0, 5, 40)
X, Y = np.meshgrid(x, y)
Z = f(X, Y)
```
现在让我们看一下仅有线的标准等高线图:
```py
plt.contour(X, Y, Z, colors='black');
```
![png](../img/8-7-1.png)
请注意,默认情况下,使用单一颜色时,负值由虚线表示,正值由实线表示。或者,可以通过``cmap``参数,指定颜色表来对线条进行颜色编码。在这里,我们还指定我们想要绘制更多的线 - 数据范围内的 20 个等距间隔:
```py
plt.contour(X, Y, Z, 20, cmap='RdGy');
```
![png](../img/8-7-2.png)
在这里,我们选择了``RdGy``(`Red-Gray`的缩写)颜色表,这是居中数据的不错选择。Matplotlib 提供了各种各样的色彩表,你可以通过在``plt.cm``模块上的 TAB 补全,在 IPython 中轻松浏览它们:
```py
plt.cm.<TAB>
```
我们的绘图看起来更好,但线条之间的空间可能有点分散。通过使用``plt.contourf()``函数(注意末尾的``f``),我们可以切换到填充的等高线图来改变它,它使用与``plt.contour()``大致相同的语法。。
另外,我们将添加一个``plt.colorbar()``命令,它会自动创建一个附加轴,带有绘图的标记的颜色信息:
```py
plt.contourf(X, Y, Z, 20, cmap='RdGy')
plt.colorbar();
```
![png](../img/8-7-3.png)
颜色条清楚地表明黑色区域是“峰值”,而红色区域是“谷值”。
这个绘图的一个潜在问题是它有些“噪点”。 也就是说,颜色阶梯是离散的而不是连续的,这并不总是所希望的。
这可以通过将等高线数设置为非常高的数量来解决,但这会使的绘图相当低效:Matplotlib必须为等高线中的每个阶梯渲染一个新的多边形。处理这个的更好方法是使用``plt.imshow()``函数,它将二维数据网格解释为图像。
以下代码显示了这一点:
```py
plt.imshow(Z, extent=[0, 5, 0, 5], origin='lower',
cmap='RdGy')
plt.colorbar()
plt.axis(aspect='image');
```
![png](../img/8-7-4.png)
但是,``imshow()``有一些潜在的问题:
- ``plt.imshow()``不接受`x`和`y`网格,所以你必须在绘图上手动指定图像的边界`[xmin, xmax, ymin, ymax]`。
- ``plt.imshow()``默认遵循标准图像数组定义,其中原点位于左上角,而不是大多数等高线图中的左下角。 显示网格化数据时必须更改此值。
- ``plt.imshow()``将自动调整轴纵横比来匹配输入数据;这可以通过设置,例如``plt.axis(aspect ='image')``来使`x`和`y`单位匹配来更改。
最后,有时可以将等高线图和图像绘图组合起来。例如,在这里我们将使用部分透明的背景图像(通过``alpha``参数设置透明度)和绘制在上面的等高线图,标签在它上面(使用``plt.clabel()``函数):
```py
contours = plt.contour(X, Y, Z, 3, colors='black')
plt.clabel(contours, inline=True, fontsize=8)
plt.imshow(Z, extent=[0, 5, 0, 5], origin='lower',
cmap='RdGy', alpha=0.5)
plt.colorbar();
```
![png](../img/8-7-5.png)
这三个函数的组合 -- ``plt.contour``,``plt.contourf``和``plt.imshow`` -- 提供了几乎无限的可能性,来在二维绘图中展示这种三维数据。这些函数中可用选项的更多信息,请参阅其文档字符串。如果你对此类数据的三维可视化感兴趣,请参阅“Matplotlib 中的三维绘图”。
\ No newline at end of file
# 8.8 直方图,分箱和密度
> 原文:[Histograms, Binnings, and Density](https://nbviewer.jupyter.org/github/donnemartin/data-science-ipython-notebooks/blob/master/matplotlib/04.05-Histograms-and-Binnings.ipynb)
>
> 译者:[飞龙](https://github.com/wizardforcel)
>
> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)
>
> 本节是[《Python 数据科学手册》](https://github.com/jakevdp/PythonDataScienceHandbook)(Python Data Science Handbook)的摘录。
简单的直方图可能是理解数据集的第一步。之前,我们预览了 Matplotlib 直方图函数(参见“比较,掩码和布尔逻辑”),一旦执行了常规的导入,它在一行中创建一个基本直方图:
```py
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
plt.style.use('seaborn-white')
data = np.random.randn(1000)
plt.hist(data);
```
![png](../img/8-8-1.png)
``hist()``函数有很多调整计算和显示的选项;这是一个更加自定义的直方图的例子:
```py
plt.hist(data, bins=30, normed=True, alpha=0.5,
histtype='stepfilled', color='steelblue',
edgecolor='none');
```
![png](../img/8-8-2.png)
``plt.hist``的文档字符串提供了其他可用自定义选项的更多信息。我发现``histtype='stepfilled'``和一些透明度``alpha``的组合,在比较几种分布的直方图时非常有用:
```py
x1 = np.random.normal(0, 0.8, 1000)
x2 = np.random.normal(-2, 1, 1000)
x3 = np.random.normal(3, 2, 1000)
kwargs = dict(histtype='stepfilled', alpha=0.3, normed=True, bins=40)
plt.hist(x1, **kwargs)
plt.hist(x2, **kwargs)
plt.hist(x3, **kwargs);
```
![png](../img/8-8-3.png)
如果你想简单地计算直方图(也就是说,计算给定桶中的点数)而不显示它,那么``np.histogram()``函数是可用的:
```py
counts, bin_edges = np.histogram(data, bins=5)
print(counts)
# [ 12 190 468 301 29]
```
## 二维直方图和分箱
就像我们通过将数字放入桶中,创建一维直方图一样,我们也可以通过将点放入通过二维的桶中,来创建二维直方图。我们将在这里简要介绍几种方法。我们首先定义一些数据 - 从多元高斯分布中抽取的``x````y``数组:
```py
mean = [0, 0]
cov = [[1, 1], [1, 2]]
x, y = np.random.multivariate_normal(mean, cov, 10000).T
```
### ``plt.hist2d``:二维直方图
绘制二维直方图的一种简单方法是使用 Matplotlib 的``plt.hist2d``函数:
```py
plt.hist2d(x, y, bins=30, cmap='Blues')
cb = plt.colorbar()
cb.set_label('counts in bin')
```
![png](../img/8-8-4.png)
就像``plt.hist``一样,``plt.hist2d``有许多微调绘图和分箱的额外选项来,这在函数的文档字符串中有很好的概述。此外,正如``plt.hist````np.histogram``中存在对应,``plt.hist2d````np.histogram2d``中也存在对应,可以按如下方式使用:
```py
counts, xedges, yedges = np.histogram2d(x, y, bins=30)
```
对于维度大于 2 的直方图分箱的推广,请参阅``np.histogramdd``函数。
### ``plt.hexbin``:六边形分箱
二维直方图创建了横跨坐标轴的正方形细分。这种细分的另一种自然形状是正六边形。为此,Matplotlib 提供了``plt.hexbin``例程,它将表示在六边形网格中分箱的二维数据集:
```py
plt.hexbin(x, y, gridsize=30, cmap='Blues')
cb = plt.colorbar(label='count in bin')
```
![png](../img/8-8-5.png)
``plt.hexbin``有许多有趣的选项,包括为每个点指定权重,以及将每个桶中的输出更改为任何 NumPy 聚合(权重的平均值,权重的标准差等)。
### 核密度估计
另一种评估多维密度的常用方法是核密度估计(KDE)。这将在“深度:核密度估计”中全面讨论,但是现在我们只是提到,KDE 可以被认为是“消去”空间中的点,并将结果相加来获得平滑函数的一种方式。
``scipy.stats``包中存在非常快速和简单的 KDE 实现。以下是在此数据上使用 KDE 的快速示例:
```py
from scipy.stats import gaussian_kde
# 拟合大小为 [Ndim, Nsamples] 的数组
data = np.vstack([x, y])
kde = gaussian_kde(data)
# 在常规网格上评估
xgrid = np.linspace(-3.5, 3.5, 40)
ygrid = np.linspace(-6, 6, 40)
Xgrid, Ygrid = np.meshgrid(xgrid, ygrid)
Z = kde.evaluate(np.vstack([Xgrid.ravel(), Ygrid.ravel()]))
# 将结果绘制为图像
plt.imshow(Z.reshape(Xgrid.shape),
origin='lower', aspect='auto',
extent=[-3.5, 3.5, -6, 6],
cmap='Blues')
cb = plt.colorbar()
cb.set_label("density")
```
![png](../img/8-8-6.png)
KDE 具有平滑长度,可以在细节和平滑度之间有效地调整(无处不在的偏差 - 方差权衡的一个例子)。有关选择合适的平滑长度的文献非常多:``gaussian_kde``使用经验法则,试图为输入数据找到近似最佳的平滑长度。
SciPy 生态系统中提供了其他 KDE 实现,每个实现都有自己的优点和缺点;例如,参见``sklearn.neighbors.KernelDensity````statsmodels.nonparametric.kernel_density.KDEMultivariate``。对于基于 KDE 的可视化,使用 Matplotlib 往往过于冗长。在“可视化和 Seaborn”中讨论的 Seaborn 库,提供了更为简洁的 API 来创建基于 KDE 的可视化。
\ No newline at end of file
# 8.9 自定义图例
> 原文:[Customizing Plot Legends](https://nbviewer.jupyter.org/github/donnemartin/data-science-ipython-notebooks/blob/master/matplotlib/04.06-Customizing-Legends.ipynb)
>
> 译者:[飞龙](https://github.com/wizardforcel)
>
> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)
>
> 本节是[《Python 数据科学手册》](https://github.com/jakevdp/PythonDataScienceHandbook)(Python Data Science Handbook)的摘录。
绘图的图例将意义赋予可视化,为各种绘图元素标识意义。我们以前看过如何创建简单的图例;在这里,我们将介绍如何在 Matplotlib 中自定义图例的位置和样式。
可以使用``plt.legend()``命令创建最简单的图例,该命令会自动为任何已标记的绘图元素创建图例:
```py
import matplotlib.pyplot as plt
plt.style.use('classic')
%matplotlib inline
import numpy as np
x = np.linspace(0, 10, 1000)
fig, ax = plt.subplots()
ax.plot(x, np.sin(x), '-b', label='Sine')
ax.plot(x, np.cos(x), '--r', label='Cosine')
ax.axis('equal')
leg = ax.legend();
```
![png](../img/8-9-1.png)
但是我们可能有很多方法想要定制这样一个图例。例如,我们可以指定位置并关闭边框:
```py
ax.legend(loc='upper left', frameon=False)
fig
```
![png](../img/8-9-2.png)
我们可以使用``ncol``命令来指定图例中的列数:
```py
ax.legend(frameon=False, loc='lower center', ncol=2)
fig
```
![png](../img/8-9-3.png)
我们可以使用圆角框(``fancybox``)或添加阴影,更改边框的透明度(`alpha`值),或更改文本周围的边距:
```py
ax.legend(fancybox=True, framealpha=1, shadow=True, borderpad=1)
fig
```
![png](../img/8-9-4.png)
可用图例选项的更多信息,请参阅``plt.legend``文档字符串。
## 为图例选择元素
我们已经看到,图例默认包含所有已标记的元素。如果这不是我们想要的,我们可以通过使用`plot`命令返回的对象,来微调图例中出现的元素和标签。``plt.plot()``命令可以一次创建多个线条,并返回已创建的线条实例的列表。将这些中的任何一个,以及我们想要标识的标签传递给``plt.legend()``将告诉它识别哪些:
```py
y = np.sin(x[:, np.newaxis] + np.pi * np.arange(0, 2, 0.5))
lines = plt.plot(x, y)
# 直线是 plt.Line2D 实例的列表
plt.legend(lines[:2], ['first', 'second']);
```
![png](../img/8-9-5.png)
我通常在实践中发现使用第一种方法更清晰,将标签应用于你想要在图例上显示的绘图元素:
```py
plt.plot(x, y[:, 0], label='first')
plt.plot(x, y[:, 1], label='second')
plt.plot(x, y[:, 2:])
plt.legend(framealpha=1, frameon=True);
```
![png](../img/8-9-6.png)
请注意,默认情况下,图例会忽略没有设置``label``属性的所有元素。
## 用于点的大小的图例
有时,图例默认值不足以满足给定的可视化效果。例如,你可能正在使用点的大小来标记数据的某些特征,并且想要创建反映这一点的图例。这是一个例子,我们将使用点的大小来表示加州城市的人口。我们想要一个标识点大小比例的图例,我们将通过绘制一些没有条目的标记数据来实现它:
```py
import pandas as pd
cities = pd.read_csv('data/california_cities.csv')
# 提取我们感兴趣的数据
lat, lon = cities['latd'], cities['longd']
population, area = cities['population_total'], cities['area_total_km2']
# 将点绘制为散点图,使用尺寸和颜色,但没有标签
plt.scatter(lon, lat, label=None,
c=np.log10(population), cmap='viridis',
s=area, linewidth=0, alpha=0.5)
plt.axis(aspect='equal')
plt.xlabel('longitude')
plt.ylabel('latitude')
plt.colorbar(label='log$_{10}$(population)')
plt.clim(3, 7)
# 这里我们创建图例
# 我们使用所需大小和标签绘制空列表
for area in [100, 300, 500]:
plt.scatter([], [], c='k', alpha=0.3, s=area,
label=str(area) + ' km$^2$')
plt.legend(scatterpoints=1, frameon=False, labelspacing=1, title='City Area')
plt.title('California Cities: Area and Population');
```
![png](../img/8-9-7.png)
图例始终引用绘图上的某个对象,因此如果我们想要显示特定的形状,我们需要绘制它。在这种情况下,我们想要的对象(灰色圆圈)不在图上,所以我们通过绘制空列表来伪造它们。另请注意,图例仅列出了指定标签的绘图元素。
通过绘制空列表,我们创建了带标签的绘图对象,由图例拾取,现在我们的图例告诉我们一些有用的信息。此策略可用于创建更复杂的可视化。
最后,请注意,对于这样的地理数据,如果我们可以显示州边界或其他特定于地图的元素,则会更清楚。为此,一个很好的工具选择是 Matplotlib 的 Basemap 附加工具包,我们将在“地理数据和 Basemap”中探讨。
## 多个图例
有时在设计绘图时,你需要在同一轴域上添加多个图例。不幸的是,这对 Matplotlib 并不容易:通过标准的``legend``接口,只能为整个绘图创建一个图例。如果你尝试使用``plt.legend()````ax.legend()``创建第二个图例,它将简单地覆盖第一个。我们可以通过从头开始创建一个新的图例艺术家来解决这个问题,然后使用较低级别的``ax.add_artist()``方法,手动将第二个艺术家添加到绘图中:
```py
fig, ax = plt.subplots()
lines = []
styles = ['-', '--', '-.', ':']
x = np.linspace(0, 10, 1000)
for i in range(4):
lines += ax.plot(x, np.sin(x - i * np.pi / 2),
styles[i], color='black')
ax.axis('equal')
# 指定第一个图例的直线和标签
ax.legend(lines[:2], ['line A', 'line B'],
loc='upper right', frameon=False)
# 创建第二个图例,并手动添加艺术家
from matplotlib.legend import Legend
leg = Legend(ax, lines[2:], ['line C', 'line D'],
loc='lower right', frameon=False)
ax.add_artist(leg);
```
![png](../img/8-9-8.png)
这是对构成任何 Matplotlib 绘图的,低级艺术家对象的窥视。
如果你检查一下``ax.legend()``的源代码(回想一下你可以在 IPython 笔记本中使用``ax.legend??``来实现),你会看到该函数只包含一些逻辑,创建合适的``Legend``艺术家,然后将其保存在``legend_``属性中,并在绘图时添加到图形中。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册