# 沿用70多年的经典数据可视化方法，如何用Python实现？

#### 01 概述

▲时间序列

1. 趋势性： 某个变量随着时间进展或自变量变化，呈现出一种比较缓慢而长期的持续上升、下降、停留的同性质变动趋向，但变动幅度可能不相等。

2. 周期性： 某因素由于外部影响随着自然季节的交替出现高峰与低谷的规律。

3. 随机性： 个别为随机变动，整体呈统计规律。

4. 综合性： 实际变化情况是几种变动的叠加或组合。预测时设法过滤除去不规则变动，突出反映趋势性和周期性变动。

• #### 代码示例①

 1from bokeh.sampledata.stocks import AAPL
2import numpy as np
3# 数据
5aapl_dates = np.array(AAPL['date'], dtype=np.datetime64)
6window_size = 30
7window = np.ones(window_size)/float(window_size)
8aapl_avg = np.convolve(aapl, window, 'same')
9# 画布
10p = figure(width=800, height=350, x_axis_type="datetime")
11# 图层
12p.circle(aapl_dates, aapl, size=4, color='darkgrey', alpha=0.2, legend='close')
13p.line(aapl_dates, aapl_avg, color='red', legend='avg')
14# 自定义属性
15p.title.text = "AAPL One-Month Average"
16p.legend.location = "top_left"
17p.grid.grid_line_alpha=0
18p.xaxis.axis_label = 'Date'
19p.yaxis.axis_label = 'Price'
20p.ygrid.band_fill_color="gray"
21p.ygrid.band_fill_alpha = 0.1
22p.legend.click_policy="hide" # 点击图例显示隐藏数据
23# 显示结果
24show(p)  

▲图1 代码示例①运行结果

• #### 代码示例②

 1import numpy as np
2from bokeh.models import ColumnDataSource, CustomJSTransform
3from bokeh.plotting import figure
4from bokeh.io import output_file, show
5from bokeh.sampledata.stocks import AAPL, GOOG
6from bokeh.transform import transform
7# 数据转换为时间类型
8def datetime(x):
9      return np.array(x, dtype=np.datetime64)
10# 画布
11plot = figure(x_axis_type="datetime", title="Normalized Stock Closing Prices",
12                          plot_width=800, plot_height=350)
13# 其他
14plot.background_fill_color = "#f0f0f0"
15plot.xgrid.grid_line_color = None
16plot.ygrid.grid_line_color = "black"
17plot.ygrid.grid_line_alpha = 0.1
18plot.xaxis.axis_label = 'Date'
19plot.yaxis.axis_label = 'Normalized Price'
20# 数据
21aapl_source = ColumnDataSource(data=dict(
22        aapl_date=datetime(AAPL['date']),
24))
25
26goog_source = ColumnDataSource(data=dict(
27        goog_date=datetime(GOOG['date']),
29))
30# CustomJSTransform
31v_func = """
32       const first = xs[0]
33       const norm = new Float64Array(xs.length)
34       for (let i = 0; i < xs.length; i++) {
35             norm[i] = xs[i] / first
36       }
37       return norm
38"""
39normalize = CustomJSTransform(v_func=v_func)
40# 绘图
41plot.line(x='aapl_date', y=transform('aapl_close', normalize), line_width=2,
42              color='#cf3c4d', alpha=0.6,legend="Apple", source=aapl_source)
43plot.line(x='goog_date', y=transform('goog_close', normalize), line_width=2,
45plot.legend.location='top_left'
46# 显示
47show(plot)  

▲图3 代码示例②运行结果

• #### 代码示例③

 1from bokeh.models import BoxAnnotation
2from bokeh.sampledata.glucose import data as data_or
3import numpy as np
4# 工具条
5TOOLS = "pan,wheel_zoom,box_zoom,reset,save"
6# 数据
7data = data_or.sort_index()['2010-03-24':'2010-03-25']
8# 画布
9p = figure(x_axis_type="datetime", tools=TOOLS, title="Glocose Readings, Oct 4th (Red = Outside Range)")
1010.
11# 绘图
12p.line(np.array(data.index.tolist(), dtype=np.datetime64), data.glucose.values, line_color='gray')
13p.circle(data.index, data.glucose, color='grey', size=1)
14# 箱形标记
17# 其他
18p.background_fill_color = "#efefef"
19p.xgrid.grid_line_color=None
20p.xaxis.axis_label = 'Time'
21p.yaxis.axis_label = 'Value'
22show(p)  

▲图3 代码示例③运行结果

• #### 代码示例④

 1import numpy as np
2from bokeh.layouts import gridplot
3from bokeh.sampledata.stocks import AAPL, GOOG, IBM, MSFT
4def datetime(x):
5    return np.array(x, dtype=np.datetime64)
6# 画布1
7p1 = figure(x_axis_type="datetime", title="Stock Closing Prices")
8p1.grid.grid_line_alpha=0.3
9p1.xaxis.axis_label = 'Date'
10p1.yaxis.axis_label = 'Price'
11# 绘图1
16p1.legend.location = "top_left"
17# 数据2
19aapl_dates = np.array(AAPL['date'], dtype=np.datetime64)
20window_size = 30
21window = np.ones(window_size)/float(window_size)
22aapl_avg = np.convolve(aapl, window, 'same')
23# 画布2
24p2 = figure(x_axis_type="datetime", title="AAPL One-Month Average")
25p2.grid.grid_line_alpha = 0
26p2.xaxis.axis_label = 'Date'
27p2.yaxis.axis_label = 'Price'
28p2.ygrid.band_fill_color = "olive"
29p2.ygrid.band_fill_alpha = 0.1
30p2.circle(aapl_dates, aapl, size=4, legend='close',
31                   color='darkgrey', alpha=0.2)
32p2.line(aapl_dates, aapl_avg, legend='avg', color='navy')
33p2.legend.location = "top_left"
34# 显示
35show(gridplot([[p1,p2]],plot_width=400, plot_height=400))

▲图4 代码示例④运行结果

• #### 代码示例⑤

 1from numpy import pi, exp, linspace, sin
2import time
3from bokeh.util.browser import view
4from bokeh.document import Document
5from bokeh.embed import file_html
6from bokeh.models.glyphs import Circle
7from bokeh.models import Plot, DatetimeAxis, ColumnDataSource, PanTool, WheelZoomTool
8from bokeh.resources import INLINE
9# 数据
10N = 200
11x = linspace(-2 * pi, 2 * pi, N)
12y = sin(x)*exp(-x)
13# 创建一组时间数据，以当前时间往后延伸24小时
14times = (linspace(0, 24*3600, N) + time.time()) * 1000
15source = ColumnDataSource(data=dict(x=x, y=y, times=times))
16# 画布
17plot = Plot(min_border=80, plot_width=800, plot_height=350, background_fill_color="#efefef")
18# 绘图
19circle = Circle(x="times", y="y", fill_color="red", size=3, line_color=None, fill_alpha=0.5)
21# 设置时间轴
24# 设置工具条
26# 显示
27show(plot)  

▲图5 代码示例⑤运行结果