# 31 数据可视化

## 大纲

* 可视化目标和类型
* matplotlib基础
* 交互动态图&#x20;
* 练习

## 可视化是什么

在大数据时代，我们周围的数据越来越丰富，量级越来越大，如何能快速的理解数据中的规律呢？一种方法就是通过后面课程将学到的数据分析进行总结归纳，还有一种方法就是用图形的方式。因为我们人类是视觉动物，有非常犀利的视觉感知系统和全面的解读系统。所以我们可以利用这种视觉功能，来帮助自身理解数据。数据绘图也是数据分析的一种重要手段。

数据绘图和一般的绘画不一样，数据绘图是将数据的一些属性反映在图形上。那么首先我们来看一下，可以利用的图形基本元素包括哪些：

* 位置，不同坐标位置上的点线可以反映不同数据的大小变化。
* 尺寸，不同点的大小，线的粗细可以反映数据的大小变化。
* 形状，不同点的形状可以反映数据的不一样，例如圆点，或三角形的点。
* 颜色，不同点或线的颜色可以反映数据的不一样。

根据不同的图形元素可以组合成各种不同的图形，以满足不同的场合需要。我们可以先来学习三种图形，分别是：

* 线图
* 点图
* 柱形图

## matplotlib绘图基础

matplotlib是python环境中非常重要的绘图模块，它的功能非常丰富，我们先来学习用它来绘制几种基本图形。

```python
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
```

先通过numpy模块来构造两个向量，x和y，x形成了横坐标的位置，y形成了sin函数的大小。

```python
x = np.linspace(0, 2*3.1415, 100)
y = np.sin(x)
```

使用linspace从0开始到$2\pi$生成100个点，然后用向量化计算直接算出100个点对应的sin值。再使用plt.plot，就绘制了基础的线图，表现了两个变量之间的函数关系。这种线图就是将数据的大小反映到坐标位置上，我们很容易观察出sin函数的这种规律性波动变化。

```python
plt.plot(x,y);
```

![](https://4271017341-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MOnn9RVvu2dqZZMH3zA%2F-MOoEnSXxhL0HpjtEFGd%2F-MOoExz1WKMx-jeg1aCR%2Foutput_11_0.png?alt=media\&token=d87dd1f7-1683-4007-95d7-4f571475e7ac)

我们还想将sin函数的最大值和最小值给标示出来，首先将这两个值计算出来，分别存到max\_min\_x和max\_min\_y中，然后在画完线图后，直接再画一个点图，使用的是scatter函数。这种通过点的位置反映两个特定数值的大小，是为了着重强调极值的位置。

```python
max_min_x = np.array([3.1415/2, 3.1415 * 3/2])
max_min_y = np.sin(max_min_x)
x = np.linspace(0, 2*3.1415, 100)
y = np.sin(x)
```

```python
plt.plot(x,y);
plt.scatter(max_min_x,max_min_y);
```

![](https://4271017341-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MOnn9RVvu2dqZZMH3zA%2F-MOoEnSXxhL0HpjtEFGd%2F-MOoF0SOywv9La6bhfgj%2Foutput_14_0.png?alt=media\&token=d76ea763-ff01-4738-84c9-be9ed72b41b8)

图形可以叠加，让我们画两个函数，分别是sin和cos函数，而且用hline画了一个横线，表示横坐标轴。这里图形自动将不同的曲线用不同的颜色绘制，体现了颜色这种图形元素的用种，让我们容易区分不同曲线的变化。

```python
x = np.linspace(0, 2*3.1415, 100)
y1 = np.sin(x)
y2 = np.cos(x)
plt.plot(x,y1)
plt.plot(x,y2)
plt.hlines(0,0,6,linestyles='dotted',color = 'grey');
```

![](https://4271017341-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MOnn9RVvu2dqZZMH3zA%2F-MOoEnSXxhL0HpjtEFGd%2F-MOoF6LRXaFAZiA0YqvP%2Foutput_16_0.png?alt=media\&token=e9d02626-32d1-4673-b7be-350adaf87d4a)

在上一节我们学习了如何来扔骰子，而且计算出来扔骰子点数的分布情况，下面我们来用条形图，把这个分布情况给形象的绘制出来。

```python
import  numpy.random as rd
dies = rd.randint(1,7,10000)
def func_count(x):
    result = dict()
    number = np.unique(x)
    for n in number:
        result[n] = x[x == n].size
    return result

dies_output = func_count(dies)
```

```python
print(dies_output)
```

```
{1: 1662, 2: 1639, 3: 1655, 4: 1662, 5: 1660, 6: 1722}
```

上面的代码和之前章节内容一样，算出了各个点数的次数，然后我们用两个列表解析把点数和对应的次数分别保存。

```python
x = [k for k,v in dies_output.items()]
y = [v for k,v in dies_output.items()]
```

然后使用plt.bar函数，来绘制出来条状图。条状图将数字大小反映到了色块的位置和尺寸上，很容易观察到这些点数的分布，基本上是相同的，这种分布就是均匀分布。

```python
plt.bar(x,y);
```

![](https://4271017341-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MOnn9RVvu2dqZZMH3zA%2F-MOoEnSXxhL0HpjtEFGd%2F-MOoFBeygn9rfdlk-uQN%2Foutput_23_0.png?alt=media\&token=277c8c8d-a009-4bd0-bdfc-0a33d04a87a3)

然后我们再绘制两个骰子扔出点数之和的条状图，还是用bar来绘制，是不是很简单。这个图形和上面图形明显不一样，这里的条状图反映出两边低，中间高的钟形分布，原因我们已经在上一课讲过了，这里更能直观的感受到这一点。这种钟形分布又被称为正态分布。

```python
die_1 = rd.randint(1,7,10000)
die_2 = rd.randint(1,7,10000)
die_sum = die_1 + die_2
dies_output = func_count(die_sum)
x = [k for k,v in dies_output.items()]
y = [v for k,v in dies_output.items()]
```

```python
plt.bar(x,y);
```

![](https://4271017341-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MOnn9RVvu2dqZZMH3zA%2F-MOoEnSXxhL0HpjtEFGd%2F-MOoFDyDzVf4PdHO4JxO%2Foutput_26_0.png?alt=media\&token=da067ae4-bdce-412c-bf5c-e8b2fa58fd69)

小结：画图是为了利用人的视觉系统，用plot画线图，scatter画点图，bar画条状图。

## 交互式绘图

之前学习的图形都是静态的，静态图的数据是给定的，如果我们某个数据变更一下，希望对应的图形也变更一下，这样更容易理解数据其中的规律，此次就需要交互性动态图。动态图需要另一个模块，就是ipywidgets模块。

```python
import ipywidgets as widgets
```

```python
def plot_func(freq):
    x = np.linspace(0, 2*3.1415,100)
    y = np.sin(x * freq)
    plt.plot(x, y)
```

我们先定义了一个sin函数的静态图绘制代码，可以看到这个代码有一个参数，就是freq，freq如果发生改变，这个图形也会发生改变，那我们就把这个freq参数做为动态图的输出参数，

```python
widgets.interact(plot_func,freq=widgets.IntSlider(min=0,max=10,step=1,value=2));
```

```
interactive(children=(IntSlider(value=2, description='freq', max=10), Output()), _dom_classes=('widget-interac…
```

![](https://4271017341-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MOnn9RVvu2dqZZMH3zA%2F-MOoEnSXxhL0HpjtEFGd%2F-MOoFGiHoy85XT3BzVOP%2Foutput_37_0.png?alt=media\&token=1575ca3c-606b-4406-8777-67b6d34b0b5c)

如果你用鼠标去滑动那个freq的滑块，这个参数就会发生改变，图中的sin曲线也因此发生改变。

另一个例子是类似的，不过这里是画一条斜线，斜线有两个参数决定，分别是截距和斜率，一个普通的静态图绘制所下所示。

```python
def plot_lines(a,b):
    x = np.linspace(-1,1,100)
    y = a+b*x
    plt.plot(x, y)
    plt.hlines(0,-1,1,linestyles='dotted',color = 'grey')
    plt.vlines(0,-1,1,linestyles='dotted',color = 'grey')
    plt.xlim((-1,1))
    plt.ylim((-1,1))
    plt.show()
```

```python
plot_lines(0.1,0.1)
```

为了让我们能交互式的绘图，可以和上面类似，定义两个可以拖动的滑块，分别代表两个参数

```python
slide1 = widgets.FloatSlider(min=-1,max=1,step=0.1,value=0.1)
slide2 = widgets.FloatSlider(min=-1,max=1,step=0.1,value=0.1)
widgets.interact(plot_lines,a=slide1, b=slide2);
```

```
interactive(children=(FloatSlider(value=0.1, description='a', max=1.0, min=-1.0), FloatSlider(value=0.1, descr…
```

如果你用鼠标去控制a,b两个滑块，你会发现图中斜线也会不一样，让人很容易理解这两个参数的意义。

小结：交互式的数据可视化，可以让我们和图形产生互动，非常形像而容易理解。

## 练习

我们来绘制骰子扔出的点数的分布图，我们想用骰子的个数来作为输入参数，这样可以看到，当扔一个骰子和几个骰子的时候骰子分布的不同。

```python
def plot_dies(n):
    dies = rd.randint(1,7,[n,10000])
    die_sum = dies.sum(0)
    dies_output = func_count(die_sum)
    x = [k for k,v in dies_output.items()]
    y = [v for k,v in dies_output.items()]
    plt.bar(x, y);
```

```python
slider = widgets.IntSlider(min=1,max=20,step=1,value=2)
widgets.interact(plot_dies,n=slider);
```

```
interactive(children=(IntSlider(value=2, description='n', max=20, min=1), Output()), _dom_classes=('widget-int…
```

一个更有趣的例子是可以自动播放上面的动态图。

```python
play = widgets.Play(
    value=1,
    min=0,
    max=20,
    step=1
)
slider = widgets.IntSlider(min=1,max=20,step=1,value=2)
widgets.jslink((play, 'value'), (slider, 'value'))
w = widgets.interactive(plot_dies,n=slider)
widgets.VBox([play,w])
```

```
VBox(children=(Play(value=1, max=20), interactive(children=(IntSlider(value=2, description='n', max=20, min=1)…
```

看到那个三角形的播放按键了吧，你点一下播放，看看会有什么有趣的事情发生。
