Plotly 绘图基础

使用 Plotly 创建交互式可视化作品

Posted by Paradise on January 19, 2021

一、简介

Ploty(plotly.py)是一个交互式的开源绘图库,它支持40多种独特的图表类型,涵盖了各种统计,财务,地理,科学和三维用例。

plotly.py 构建在 Plotly JavaScript 库(plotly.js)之上,使 Python 用户可以创建基于 Web 的漂亮的交互式可视化效果,这些可视化效果可以显示在 Jupyter notebook 中,可以保存到独立的 HTML 文件中,也可以作为纯 Python – 使用 Dash 构建 Web 应用程序。

由于与 orca 图像导出实用程序进行了深度集成,plotly.py 还为非 Web 上下文提供了强大的支持,包括桌面编辑器(例如 QtConsole,Spyder,PyCharm)和静态文档发布(例如,将 notebook 导出为具有高质量矢量图像的 PDF)。

本文记录 Plotly 的基础图表绘制代码,更详细内容查看官方文档:Getting Started with Plotly in Python

二、基础

安装完 plotly,可以看到其目录下含有哪些 module。注意如果是较久之前安装的版本,需要执行 pip install plotly --upgrade 更新一下。4.0 后的版本改动较大,绘图的函数和参数等都有变化。本文最近一次更新是 v4.6.0。

png

plotly 主要有线上、离线、jupyter-notebook 几种绘图方式,分别用到了以上不同模块中的脚本。

这里存在一个问题,起初尝试的时候可以直接创建一个 plotly.graoh_objs._figure.Figure 对象。执行 figure.show() 便会自动启动一个 localhost 服务在浏览器显示所绘制的图表。但是后面再试又不行了,一直显示无法连接 localhost。可能是系统相应设置的问题,暂时忽略。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import plotly
import plotly.plotly as py
import  plotly.graph_objs as go

plotly.tools.set_credentials_file(username='acount', api_key='generated_key')

'''在线绘图:需要获取 plotly 的 API,使用 plotly 提供的云服务'''
# 生成graph_objs对象
trace = go.Scatter(x=[0,1,2,3,4], y=[1,2,3,4,5])
py.plot(data, filename='test', auto_open=True)

'''离线绘图:输出 html 文件,可在浏览器打开交互式图表'''
plotly.offline.plot(
    {'data': [go.Scatter(x=[0,1,2,3,4], y=[1,2,3,4,5])],
    'layout': go.Layout(title='test figure')
    },
    auto_open=True
)

'''集成到 jupyter notebook:更改设置,plot 函数改为 iplot 函数.'''
plotly.offline.init_notebook_mode(connected=True)
plotly.offline.iplot(
    # 内容同上
    # ...
)
# 强烈不推荐使用 jupyter notebook,没有理由...

如果不使用 jupyter notebook,为解决绘图时不能实时更新图片的问题,可以利用 dash 建立本地服务。首先 pip install dash,然后定义以下函数。在浏览器链接 localhost:8050 ,每次绘图后调用函数,再刷新页面即可。

1
2
3
4
5
6
7
8
9
10
11
"""创建本地仪表板服务"""

import dash
import dash_core_components as dcc
import dash_html_components as html

def show_fig(fig):
    app = dash.Dash()
	app.layout = html.Div([dcc.Graph(figure=fig)])
	app.run_server(debug=True, use_reloader=False)


下文主要使用 titanic 数据集

1
2
3
# 这里主要考虑数据集包含绘图需要的数据类型,绘制的图可能并没有实际意义
df = pd.read_csv('titanic.csv').drop(['name'], axis=1)
df.head()
survived pclass sex age sibsp parch ticket fare cabin embarked
0 3 male 22 1 0 A/5 21171 7.25 nan S
1 1 female 38 1 0 PC 17599 71.2833 C85 C
1 3 female 26 0 0 STON/O2. 3101282 7.925 nan S
1 1 female 35 1 0 113803 53.1 C123 S
0 3 male 35 0 0 373450 8.05 nan S

三、绘图入门

散点图与折线图

使用 plotly.express 绘制散点图与折线图(4.0以上版本)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import plotly.express as px

# 先将数值型转换成离散的分类变量,用于分类
df.survived = df.survived.map({1:'yes', 0:'no'})

# 绘制散点图
fig1 = px.scatter(df, x='age', y='fare', color='survived', size='pclass')
# fig1.show()		# 此处启动localhost服务,在浏览器显示图表

# 绘制折线图
x = np.linspace(-10, 10, 1000)
fig2 = px.line(
    x=x, y=np.sin(x)*np.cos(10*x), 
    labels={'x': 't', 'y': 'sin(t)cos(10t)'}, 
    title='高频调制波形示例'
)

# 由于前文说到的localhost服务出错,这里定义函数保存图片到本地
def save_fig(fig, name='output.html'):
    html = fig.to_html()
    with open(name, 'w') as f:
        f.write(html)
    print(f'成功输出网页:{name}')

# 输出图片,效果如下
save_fig(fig1, 'scatter.html')
save_fig(fig2, 'line.html')

▲ 查看上图交互式网页

▲ 查看上图交互式网页

使用 plotly.graph_objs 绘制散点图和折线图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import plotly.graph_objs as go

# 数据
x = np.linspace(-10, 10, 1000)
y1 = np.sin(x)
y2 = np.sin(x)*np.cos(10*x)
y3 = np.cos(10*x)

# 使用 Figure 对象在画布上添加不同图形
fig = go.Figure()

fig.add_trace(
    go.Scatter(x=x, y=y1, mode='markers', name='sin(x)')
)
fig.add_trace(
    go.Scatter(x=x, y=y2, mode='lines+markers', name='sin(x)cos(10x)')
)
fig.add_trace(
    go.Scatter(x=x, y=y3, mode='lines', name='cos(10x)')
)

# 调整细节
fig.update_traces(marker_size=3, line_width=1)
fig.update_layout(title='高频调制波波形示例', xaxis_zeroline=False)

save_fig(fig, 'line_scatter.html')

▲ 查看上图交互式网页

条形图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 使用 plotly.express 绘制条形图
group_agg = df[['pclass', 'survived', 'age']].groupby('pclass').mean()
group_agg['pclass'] = group_agg.index

fig = px.bar(group_agg, x='pclass', y='survived', color='age')
save_fig(fig, 'barplot_with_color.html')

# 使用 plotly.graph_objs 绘制多个条形图
group_agg = df[['sex', 'pclass', 'survived']].groupby(['sex', 'pclass']).mean()
group_agg['pclass'] = [1,2,3,1,2,3]
female = group_agg.loc[('female', slice(None)), :]
male = group_agg.loc[('male', slice(None)), :]

fig = go.Figure(
    data=[
        go.Bar(
            x=female.pclass, 
            y=female.survived, 
            name='female', 
            marker_color='rgb(240,90,55)'
            ),
        go.Bar(
            x=male.pclass, 
            y=male.survived, 
            name='male', 
            marker_color='rgb(100,200,200)'
            )
    ]
)

save_fig(fig, 'group_barplot.html')

▲ 查看上图交互式网页

▲ 查看上图交互式网页

饼图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 使用 plotly.express 绘制饼图

# 查看每个包厢区域的生还率
df.cabin = ['NULL' if type(c)==float else c[0] for c in df.cabin]
group_agg = df[['cabin', 'survived']].groupby('cabin').mean()
group_agg['cabin_header'] = group_agg.index
group_agg['cabin_header'][7] = 'None'
group_agg['passenger_count'] = df.groupby('cabin').count().survived

fig = px.pie(
    group_agg, 
    values='passenger_count', 
    names='cabin_header',
    title='Passenger Number & Survived Rate in Different Cabin Area',
    hover_data=['survived'], 
    labels={'survived': 'Survived Rate'}
)
fig.update_traces(textposition='inside', textinfo='percent+label')

save_fig(fig, 'pieplot.html')

▲ 查看上图交互式网页