因为plotly用着还不熟练,我把我遇到的一些plotly调用问题总结了一下:
疫情期间,工作‘过于‘繁忙。。。教程早已编好,文稿却没更出来。。。
(伪)鲁迅曾经说过:所有的数据都应该被‘画’出来,而不是‘写’出来。
自接触数据科学起,我就异常热衷于’画‘出更好的数据图(逼死强迫症)。作为一个曾经的通信人,Matlab告诉我,不能交互的数据图永远不算完美。什么matplotlib,seaborn,甚至ggplot。我只想说,普通。。。直到 plotly出现。
plotly官方文档: https://plotly.com/python
plotly是一个可交互的 开源 开源 开源 python数据可视化库。在顶层通过 JavaScript(plotly.js)库生成web-based 可视化图表。
(可以直接生成网页,还能集成在jupyter-notebook | jupyter-lab(需要额外插件)| VS code 中直接显示)
另外,plotly 作为python 数据生态中的重要一环,也创建了相应的网页数据报表 – Dash ,对标R shiny,Tableau,MS PowerBI(后两个为商业软件,集成环境更优秀,而且价格也挺贵。。。)
当然, plotly & Dash也分为开源版本和商用版本, 并且4.0版本之前都可以使用online/offline 两种模式。其中online模式需要注册账号, 上传的图表可以使用Chart Studio对细节进行更改。 4.0之后的版本已经将online模式彻底移植到 chart-studio 中,
pip 和conda 都可以直接安装, 截止到目前为止 最新版本为 4.6.0 (plotly >=4.0.0 只有offline 模式)
pip install plotly==4.6.0
考虑到各个packages 的版本依赖关系, 更推荐通过conda安装
conda install -c plotly plotly==4.6.0
我一直用jupyter-lab, 额外的extensions安装如下 (jupyter 安装extensions 需要提前安装 node.js。。。):
conda install jupyterlab
conda install ipywidgets
jupyter labextension install @jupyter-widgets/[email protected] --no-build
jupyter labextension install [email protected] --no-build
jupyter labextension install [email protected] --no-build
jupyter lab build
在最开始使用plotly的时候,我唯一的一个疑问就是,搞不清楚什么时候使用什么模块。为此,特意去研究了一下官方提供的API教程。
plotly分为 5个重要子模块:
数据来源: 约翰霍普金森大学 - 新冠病毒全球感染人数 - Github 开源数据
编程环境:
- Python version = 3.8
- jupyter-lab version = 1.2.6
- plotly version = 4.6.0
- numpy version = 1.18.1
- pandas version = 1.0.3
- cufflinks version = 0.17.3
# import basic libs
import os
import pandas as pd
import numpy as np
# 直接从github读取数据
df = pd.read_csv('https://raw.githubusercontent.com/CSSEGISandData/COVID-19/web-data/data/cases_time.csv', error_bad_lines=False )
df.loc[:,'Last_Update'] = pd.to_datetime(df.loc[:,'Last_Update'], format='%m/%d/%y')
print(df.shape) # output: (21384, 16)
# 国家/城市坐标 & 人口数据
location_lookup_table = pd.read_csv('https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/UID_ISO_FIPS_LookUp_Table.csv', error_bad_lines=False )
数据基本情况:
# 疫情统计时间
df.loc[:,'Last_Update'].min() # Timestamp('2020-01-22 00:00:00')
df.loc[:,'Last_Update'].max() # Timestamp('2020-04-18 00:00:00')
从时间角度看,基本就是,国内暴发疫情之后的第一阶段。
就像写网页需要CSS布局文件一样,Plotly也需要先创建一个布局 Layout
Plotly是用js 编译生成图像, 配置文件 基本就是json格式,所以各个参数可以用字典直接定义。
下面的例子里,我简单的设定了一些常用的参数,方便直接copy 使用
import plotly as py
from plotly import graph_objects as go
from plotly import subplots
layout_default = go.Layout(
# color theme
template='plotly_dark',
# set title
title = dict(
text='Default Title',
font={
'size':30,
'color':'#444'
},
x=0.5, #[0,1,'auto']
y=0.9 # [0,1, 'auto']
),
# set axis
xaxis=dict(
visible=True,
color='#444',
title='default xaxis' # or dict
),
yaxis=dict(
visible=True,
color='#444',
title='default yaxis', # or dict
type='-', # one of ( "-" | "linear" | "log" | "date" | "category" | "multicategory" )
#range=[1,2]
),
# set Figure's size
autosize=False,
height=600, # in pixel
width=1100,
# set Legend
showlegend=True
)
# 准备数据
countries = ['DEU', 'ESP', 'FRA', 'GBR', 'ITA', 'USA']
df_country = df[(df['Province_State'].isna())&(df['Last_Update'] >= '2020-03-01')]
# pivot 各个国家的确诊人数
data= df_country.pivot_table(index='iso3',columns='Last_Update',values='Confirmed', fill_value=0, aggfunc='mean').loc[countries]
# 创建 figure
fig = go.Figure(layout=layout_default)
# x坐标
x= data.columns.strftime('%Y-%m-%d').values.tolist()
# 画多条曲线
for idx in data.index:
# 官方API: https://plotly.com/python/reference/
fig.add_trace(
go.Scatter(
x =x,
y = data.loc[idx].values.tolist(),
text = data.loc[idx].values.tolist(),
mode = 'lines+markers',
name= location_lookup_table[location_lookup_table['iso3'] == idx].iloc[0]['Country_Region'],
hovertext = 'Population:{}'.format(int(location_lookup_table[location_lookup_table['iso3'] == idx].iloc[0]['Population'])),
hoverinfo = 'all',# Examples: "x", "y", "x+y", "x+y+z", "all"
opacity=0.5
)
)
# 略微更改一下布局
fig.update_layout(
title = dict(
text='疫情大国确诊总人数',
font={'size':30},
x=0.5, #[0,1,'auto']
y=0.9 # [0,1, 'auto']
),
)
# 快速更改axis
fig.update_xaxes(
title_text="日期 加粗"
)
fig.update_yaxes(
title_text="确诊人数 斜体"
)
# 画图像
fig.show()
看了其他的API, 我发现如果要创建多个子图的画布, 最好还是直接从底层graph_objects 配合 subpots 来搭建更快捷.
如果需求仅仅是EDA过程中的数据可视化 那么 plotly.express很好的适配了pandas.DataFrame, 真的真的真的很方便!
下
import plotly.express as px
fig = px.scatter_geo(data_frame=df_country,
locations="iso3",
color="Incident_Rate",
hover_name="Country_Region",
size="Confirmed",
animation_frame=df_country["Last_Update"].astype(str),
projection="natural earth",
size_max=100,
width=1200, height=700)
fig.update_layout(
template='plotly_dark'
)
fig.show()
# pandas.dataframe --> plotly.graph_objects.table
def TableFromPandas(df):
columns = df.columns
return go.Table(
header=dict(values=list(columns),
align='left'),
cells=dict(values=[df[i] for i in columns],
align='left')
)
fig = go.Figure(
data=[TableFromPandas(df_country)]
)
fig.show()
其实 总体看起来,plotly底层API graph_objects参数繁多,可操作空间非常大, 配合subplots,可以制作出非常精良的报表!
用于EDA过程中的数据可视化却略有些繁琐。相对而言, plotly.express在平时相对更加实用!
另外还有一个package 叫做 cufflinks 日常用起来更加方便, 可以通过 df.iplot() 直接调用plotly API , 平时用来画些简单的分布图啊, 折线图啊 只能是真香 !
import cufflinks as cf
cf.go_offline()
cf.set_config_file(offline=False, world_readable=True)
# 数据没变
df_country.pivot_table(columns='iso3',index='Last_Update',values='Confirmed', fill_value=0, aggfunc='mean')[countries].iplot(opacity=0.5, mode = 'lines')
下次更新内容:
PS : 话说,曾经用Dash制作过一个简单的审阅学生考试成绩的报表,只不过是法语版的,有需要的朋友可以拿走:
https://github.com/lhaippp/Dash_Student_Management_System
PPS:上周收到了祖国爸爸发来的急救包(不是只给留学生 lol)!口罩,莲花清瘟胶囊,消毒湿巾一应俱全。一看日期,3月23号生产!从生产到运输直到送达, 在没有物流的情况下,10多天就能全球达!