0%

Python-数据可视化

使用 Python 进行数据可视化的最佳实践。如:

  • Streamlit:机器学习过程快速 web 可视化的工具,纯 Python 开发 web app。牛*
    • tensorboard:交互性不如 Streamlit,OUT
  • pyecharts:基于百度开源的数据可视化工具库 echarts。原 js 的 Python 接口。适合数据工程 demo 展示
  • streamlit-echarts:两大神器的合体
  • Altair:让数据科学家更多地关注数据本身和其内在联系的库
  • matplotlib:2D 绘图库,Python 可视化最基本、最常用的库。偏向学术(不够好看),但大家用得多,得会基本操作
  • wordcloud:以词云为对象,依据词语出现的频率绘制词云,可设定词云的大小、颜色、形状等
  • mapbox:处理地理数据引擎更强的可视化工具库
  • Geoplotlib:地图可视化

概述

数据可视化库

Matplotlib:元老级,使用广泛,Python 可视化最基本、最常用的库。设计与 MATLAB 相似,偏向学术(不够好看),OUT

Seaborn:基于 Matplotlib 的高级可视化效果库,几行代码创建漂亮的图表偏向统计作图,即 Matplolib 的包装,OUT

Pyecharts:【当前首选】国产,生成 Echarts 图表,效果美观

Bokeh:交互式 web 可视化库,基于图像语法,可方便地将数据输出为 JSON 对象、HTML 文档或交互式 Web 应用程序,支持流媒体和实时数据。

  • 基于 Javascript 的交互可视化库,python 画图保存为 html。坑多,语法晦涩难懂。OUT

Plotly:数据可视化的在线平台,与 Bokeh 一样,Plotly 的强项在于制作交互式图,但它提供了一些在大多数库中没有的图表,如等高线图、树状图和 3D 图表。

  • 配色好看,底层为 plotly.js,是基于 D3.js、stack.gl 和 SVG,以 JavaScript 在网页上实现图形展示功能。很强大,也很复杂。有 freemium 与 premium 两种帐户,不,我要全功能,不行?OUT
  • plotly 是很强,但是接口设计和文档的真的是反人类

Altair 是一个基于 Vega-lite 的声明性统计可视化库,声明意味着用户只需要提供数据列与编码通道之间的链接,例如,x轴、y轴、颜色等,其余的绘图细节它会自动处理,声明使 Altair 变得简单、友好和一致,用户使用 Altair 可以轻松设计出有效且美观的可视化代码。

  • OUT:没有饼图?这种基本的图都没有,怀疑它的靠谱性。

数据可视化流程

确定目标,选择图形

  • 可视化的目的:更清晰地反映数据的某个特征,使分析、评估变得清晰。
  • 数据大屏样式:flex 布局 + echarts + UI 组件 + 相关 css/js 效果
  • 点: scatter plot:二维数据,适用于简单二维关系; ^d227a3
  • 线: line plot:二维数据,适用于时间序列;
  • 柱状: bar plot: 二维数据,适用于类别统计;
  • 颜色: heatmap:适用于展示第三维度

提炼数据,构建关系

  • 数据指标
  • 关系:分布、构成、比较、联系、变化
  • 用户关注的重点指标
  • 避免数据中的极端值,异常值,或过多的分类等
  • 数据
    • 合并: merge,concat,combine_frist(类似于数据库中的全外连接)
    • 重塑: reshape;轴向旋转:pivot(类似 excel 数据透视表)
    • **去重:**drop_duplicates
    • **映射:**map
    • **填充替换:**fillna,replace
    • **重命名轴索引:**rename

图表选择

  • 由数据间的相互关系确定图表
    • 选择最合适的图表来可视化,切记不要炫技,可视化的目的是简洁明了,突出主题。
  • 趋势型:某一变量随另一变量的变化趋势,如时间序列数据的可视化;
    • 折线图:数据在一个连续时间间隔上的变化。连续数值的变化趋势
    • 柱状图
    • 箱线图:五个数字表示:最大值,最小值,中位数,下四分位数、上四分位数
  • 对比型:对比两组或两组以上的数据,如班级的男女生数量比较
    • 条形图(柱状图):用垂直或水平的柱子显示类别之间的数值比较。多个分类的
  • 比例型:数据总体和各个组成部分之间的比例关系。
    • 饼图:以弧度大小表示不同分类的占比。一般不超过九个分类
  • 相关性分析:商品的单价与销售量的关系
    • 散点图 (X-Y 图):将所有数据以点的形式展现在直角坐标系上。
  • 分布型:展现一组数据的分布情况,如描述性统计中的集中趋势、离散趋势、偏态与峰度等。
    • 常采用直方图
  • 区间型:显示同一维度上值的不同分区差异,常用来表示进度情况
    • 仪表盘图:拟物化(汽车速度表)图表,刻度表示度量,指针不示维度,指针角度表示数值
  • 关联型:用于直观表示不同数据之间的相互关系,如包含关系、层级关系、分流关系、联结关系等
  • 漏斗转化分析:分析具有明确流程节点转化率的资料分析场景,如浏览商品到下单
    • 漏斗图
  • 地理型:数据在不同地理区域上的分布情况,如 各省的人口数量。
    • 点地图、区域地图、热力地图、流向地图等
    • 热力图:Heat Map:以彩虹色系展现分布的
  • 日历图:分析与时间规律相关的分布数据。如 Github
  • 分布分析:不同产品类型的销售金额
    • 饼图、堆积柱状图
  • 周期性数据分析:如企业经营状况:收益性\生产性、流动性、安全性等 。
    • 快速对比、定位短板指标
    • 雷达图:表示多维数据的图表,每个维度数据对应一个坐标轴。

可视化布局

  • 针对多个可视化图表,进行各区域的布局设计:
    • 聚焦:凸显主体(重要数据),吸引用户,提高效率
    • 平衡:合理利用空间,保持元素间的空间平衡,提高设计美感
    • 简洁:突出重点,避免冗余
  • 图表形状,颜色,边框,背景,网格等辅助元素,一定程度上可以帮助用户聚焦,但使用过当的情况下会使得图表杂乱,视觉上不够聚焦,影响观看

Streamlit

Streamlit:机器学习过程快速 web 可视化的工具,纯 Python 开发 web app。牛*

tensorboard:交互性不如 Streamlit,OUT
anvil:出现了一个功能比 Streamlit 强得多,能真正替换掉 flask 的东西,但它只能在 web 上 code,以及有些功能需收费,以及功能看起来好复杂,观望中【202107】
Pynecone:需要 nodejs?OUT

类似插件的库

-streamlit-elements:一堆功能,有个可拖拽的元素不错

  • 特点:
    • 组件机制:组件为变量,Streamlit 没有回调,每次交互都是简单的返回,以保证代码的干净
    • 一改一执行:自上而下运行,每次改变网页中的某个控件的值 a 或修改源代码 时,都会重新执行脚本。
    • 实时看效果:开发速度快,修改方便,监视每次修改,实进更新效果
    • 数据重用:缓存机制,对于机器学习导入的大规模数据集,在热更新中不必重复加载数据。
    • No 前端:不需要 web 相关的 css、js,**JS
    • 缺点:前端界面固定,不能随意调整控件位置,待发展(目前基本够用)
  • 参考资料:官方文档
  • 2021 年 10 月 5 日,发布了 1.0.0 版本

基本使用

  • 默认端口 8501,被占用时会递增
1
pip install streamlit
1
2
3
4
5
6
7
8
9
10
11
12
# 运行官方示例 demo
streamlit hello

# 运行本地脚本
streamlit run app.py
python -m streamlit run app.py
# 运行指定带 streamlit 的 py 文件
streamlit run app.py --server.port 80 --server.maxUploadSize 1024
# 清除缓存
streamlit cache clear
# 运行 web 上的.py
streamlit run https://.../app.py
1
2
3
4
5
6
7
8
# 修改端口
vi ~/.streamlit/config.toml

[server]
port = 80

# 查看配置
streamlit config show
1
import streamlit as st

配置

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
st.set_page_config(
page_title='项目名', # 页面标题
page_icon='', # 页面图标
layout='wide', # centered居中 or wide整个屏幕
initial_sidebar_state="auto", # 边栏应如何开始,auto 自动,expanded 展开,collapsed 隐藏
menu_items:dict) # 配置出现在应用程序右上用的菜单
>>> st.set_page_config(
... page_title="Ex-stream-ly Cool App",
... page_icon="🧊",
... layout="wide",
... initial_sidebar_state="expanded",
... menu_items={
... 'Get Help': 'https://www.extremelycoolapp.com/help',
... 'Report a bug': "https://www.extremelycoolapp.com/bug",
... 'About': "# This is a header. This is an *extremely* cool app!"
... }
... )


streamlit --help
# 查看可选配置
streamlit config show

streamlit.get_option(key)
# 配置参数
streamlit.set_option(key,value)
# client.caching
# client.displayEnabled
# deprecation.*

streamlit.help(key)

.streamlit/config.toml

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
[server]
runOnSave = true
enableCORS=true
[runner]
postScriptGC = false

# Below are all the sections and options you can have in ~/.streamlit/config.toml.

[global]

# By default, Streamlit checks if the Python watchdog module is available and, if not, prints a warning asking for you to install it. The watchdog module is not required, but highly recommended. It improves Streamlit's ability to detect changes to files in your filesystem.
# If you'd like to turn off this warning, set this to True.
# Default: false
# disableWatchdogWarning = false

# If True, will show a warning when you run a Streamlit-enabled script via "python my_script.py".
# Default: true
# showWarningOnDirectExecution = true

# DataFrame serialization.
# Acceptable values: - 'legacy': Serialize DataFrames using Streamlit's custom format. Slow but battle-tested. - 'arrow': Serialize DataFrames using Apache Arrow. Much faster and versatile.
# Default: "arrow"
# dataFrameSerialization = "arrow"


[logger]

# Level of logging: 'error', 'warning', 'info', or 'debug'.
# Default: 'info'
# level = "info"

# String format for logging messages. If logger.datetimeFormat is set, logger messages will default to `%(asctime)s.%(msecs)03d %(message)s`. See [Python's documentation](https://docs.python.org/2.6/library/logging.html#formatter-objects) for available attributes.
# Default: "%(asctime)s %(message)s"
# messageFormat = "%(asctime)s %(message)s"


[client]

# Whether to enable st.cache.
# Default: true
# caching = true

# If false, makes your Streamlit script not draw to a Streamlit app.
# Default: true
# displayEnabled = true

# Controls whether uncaught app exceptions are displayed in the browser. By default, this is set to True and Streamlit displays app exceptions and associated tracebacks in the browser.
# If set to False, an exception will result in a generic message being shown in the browser, and exceptions and tracebacks will be printed to the console only.
# Default: true
# showErrorDetails = true


[runner]

# Allows you to type a variable or string by itself in a single line of Python code to write it to the app.
# Default: true
# magicEnabled = true

# Install a Python tracer to allow you to stop or pause your script at any point and introspect it. As a side-effect, this slows down your script's execution.
# Default: false
# installTracer = false

# Sets the MPLBACKEND environment variable to Agg inside Streamlit to prevent Python crashing.
# Default: true
# fixMatplotlib = true

# Run the Python Garbage Collector after each script execution. This can help avoid excess memory use in Streamlit apps, but could introduce delay in rerunning the app script for high-memory-use applications.
# Default: true
# postScriptGC = true

# Handle script rerun requests immediately, rather than waiting for script execution to reach a yield point. Enabling this will make Streamlit much more responsive to user interaction, but it can lead to race conditions in apps that mutate session_state data outside of explicit session_state assignment statements.
# Default: false
# fastReruns = false


[server]

# List of folders that should not be watched for changes. This impacts both "Run on Save" and @st.cache.
# Relative paths will be taken as relative to the current working directory.
# Example: ['/home/user1/env', 'relative/path/to/folder']
# Default: []
# folderWatchBlacklist = []

# Change the type of file watcher used by Streamlit, or turn it off completely.
# Allowed values: * "auto" : Streamlit will attempt to use the watchdog module, and falls back to polling if watchdog is not available. * "watchdog" : Force Streamlit to use the watchdog module. * "poll" : Force Streamlit to always use polling. * "none" : Streamlit will not watch files.
# Default: "auto"
# fileWatcherType = "auto"

# Symmetric key used to produce signed cookies. If deploying on multiple replicas, this should be set to the same value across all replicas to ensure they all share the same secret.
# Default: randomly generated secret key.
# cookieSecret = "cce01fff7bfc768ed284ef97e363d965e5f290f69d98a8cc725d2e5de31bd944"

# If false, will attempt to open a browser window on start.
# Default: false unless (1) we are on a Linux box where DISPLAY is unset, or (2) we are running in the Streamlit Atom plugin.
# headless = false

# Automatically rerun script when the file is modified on disk.
# Default: false
# runOnSave = false

# The address where the server will listen for client and browser connections. Use this if you want to bind the server to a specific address. If set, the server will only be accessible from this address, and not from any aliases (like localhost).
# Default: (unset)
# address =

# The port where the server will listen for browser connections.
# Default: 8501
# port = 8501

# The base path for the URL where Streamlit should be served from.
# Default: ""
# baseUrlPath = ""

# Enables support for Cross-Origin Request Sharing (CORS) protection, for added security.
# Due to conflicts between CORS and XSRF, if `server.enableXsrfProtection` is on and `server.enableCORS` is off at the same time, we will prioritize `server.enableXsrfProtection`.
# Default: true
# enableCORS = true

# Enables support for Cross-Site Request Forgery (XSRF) protection, for added security.
# Due to conflicts between CORS and XSRF, if `server.enableXsrfProtection` is on and `server.enableCORS` is off at the same time, we will prioritize `server.enableXsrfProtection`.
# Default: true
# enableXsrfProtection = true

# Max size, in megabytes, for files uploaded with the file_uploader.
# Default: 200
# maxUploadSize = 200

# Max size, in megabytes, of messages that can be sent via the WebSocket connection.
# Default: 200
# maxMessageSize = 200

# Enables support for websocket compression.
# Default: false
# enableWebsocketCompression = false


[browser]

# Internet address where users should point their browsers in order to connect to the app. Can be IP address or DNS name and path.
# This is used to: - Set the correct URL for CORS and XSRF protection purposes. - Show the URL on the terminal - Open the browser
# Default: "localhost"
# serverAddress = "localhost"

# Whether to send usage statistics to Streamlit.
# Default: true
# gatherUsageStats = true

# Port where users should point their browsers in order to connect to the app.
# This is used to: - Set the correct URL for CORS and XSRF protection purposes. - Show the URL on the terminal - Open the browser
# Default: whatever value is set in server.port.
# serverPort = 8501


[mapbox]

# Configure Streamlit to use a custom Mapbox token for elements like st.pydeck_chart and st.map. To get a token for yourself, create an account at https://mapbox.com. It's free (for moderate usage levels)!
# Default: ""
# token = ""


[deprecation]

# Set to false to disable the deprecation warning for the file uploader encoding.
# Default: true
# showfileUploaderEncoding = true

# Set to false to disable the deprecation warning for using the global pyplot instance.
# Default: true
# showPyplotGlobalUse = true


[theme]

# The preset Streamlit theme that your custom theme inherits from. One of "light" or "dark".
# base =

# Primary accent color for interactive elements.
# primaryColor =

# Background color for the main content area.
# backgroundColor =

# Background color used for the sidebar and most interactive widgets.
# secondaryBackgroundColor =

# Color used for almost all text.
# textColor =

# Font family for all text in the app, except code blocks. One of "sans serif", "serif", or "monospace".
# font =

会话状态

  • 重运行(rerun)间共享变量
  • session state 只可能在应用初始化时被整体重置。而 rerun 不会重置 session state。可以理解成“状态缓存”。
    • 如存储登录状态(通过回调函数将 False 变 True)
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
# 对每个用户会话,会话状态是在重新运行之间共享变量的一种方式
st.session_state['key']=value

if 'key_name' not in st.session_state:
st.session_state['key_name']='value'
# st.session_state.key_name = 'value'

# 删除
del st.session_state['key_name']
for key_ in st.session_state.keys():
del st.sessiooon_state[key_]


# 与回调结合
def form_callback():
st.write(st.session_state.my_slider)
st.write(st.session_state.my_checkbox)

with st.form(key='my_form'):
slider_input = st.slider('My slider', 0, 10, 5, key='my_slider')
checkbox_input = st.checkbox('Yes or No', key='my_checkbox')
submit_button = st.form_submit_button(label='Submit', on_click=form_callback)

# 初始化
if 'my_button' not in st.session_state:
st.session_state.my_button = True
# Streamlit will raise an Exception on trying to set the state of button

st.button('Submit', key='my_button')

带参数访问

1
2
3
4
st.experimental_get_query_params()

http://localhost/?show_map=True&selected=asia&selected=america
{'show_map': ['True'], 'selected': ['asia', 'america']}

自定义组件

  • 可以使用 streamlit.components.v1.htmlstreamlit.components.v1.iframe 来使用 HTML 的相关资源,but,不这么做,因为就是为了不用 HTML 才用的 Streamlit

常用控件

文本控件

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
32
33
34
35
36
37
38
# 标题,anchor不设置则会用body生成
st.title('标题', anchor='锚点1')
st.header(body='header', anchor='锚点2')
st.subheader('subheader')

# 纯文本,固定宽度和预先格式化的文本
test_text=st.text('纯文本')
test_text.text('ddd') # 更新 text

# 缩小字体
st.caption('test')

# markdown
st.markdown('**加粗**',unsafe_allow_html=False) # 是否转义 HTML 标记

# latex
st.latex(r'''
a + ar + a r^2 + a r^3 + \cdots + a r^{n-1} =
\sum_{k=0}^{n-1} ar^k =
a \left(\frac{1-r^{n}}{1-r}\right)
''')


# write:智能识别并显示:文本、numpy 数据、pandas 数据、matplotlib 图像、Altair 图像
st.write(1111)
st.write(pd.DataFrame({
'first column': [1, 2, 3, 4],
'second column': [10, 20, 30, 40],
}))
# 更智能的识别并显示:直接写变量或文字,会默认调用`st.write`
df = pd.DataFrame({'col1': [1,2,3]})
df

x = 10
'x:', x

# 代码
st.code("print('Hello World')",language='python')

数据控件

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
32
33
34
35
36
37
38
39
# 指标
st.metrics("身高", 178, 1)
st.metrice(label, # 指标标题
value, # 值,None呈现为长破折号
delta=None, # 负数或减号开头的str,箭头向下文本为红色,否则为绿色,None则不显示增量指示器
delta_color='normal') # normal/inverse/off:灰色
# json
st.json()

# pandas.DataFrame ,pandas.Styler ,numpy.ndarray,iterator,dict
st.dataframe(data=None,
width=None, # 像素级宽度。如果没有,则使用基于页面宽度的默认宽度。
Height=None)
# 对于pandas.Styler,用于设置底层DataFrame的样式,支持自定义单元格值和颜色
# Streamlit 的旧版 DataFrame 序列化不支持 Pyarrow 表(即config.dataFrameSerialization = "legacy")。要使用 pyarrow 表,请通过更改配置设置config.dataFrameSerialization = "arrow" 来

df = pd.DataFrame(
np.random.randn(10, 20),
columns=('col %d' % i for i in range(20)))
st.dataframe(df)
st.dataframe(dataframe.style.highlight_max(axis=0))

# 静态表格
st.table(df) # pandas.DataFrame,pandas.Styler,numpy.ndarray,Iterable,dict,None

# 变化数据
df1 = pd.DataFrame(
np.random.randn(50, 20),
columns=('col %d' % i for i in range(20)))
my_table = st.table(df1)
time.sleep(5)
df2 = pd.DataFrame(
np.random.randn(50, 20),
columns=('col %d' % i for i in range(20)))
my_table.add_rows(df2)

# 在现有图、表、数据框上修改数据
DeltaGenerator.add_rows(data=None,
**kwargs)

图表控件

  • Matplotlib、Altair, deck.gl 等
  • 优先使用 altair,altair 也不太行,最终选择了 streamlit-pyecharts
1
2
3
4
5
6
7
8
9
10
11
12
# Altair 图表
df_data=pd.DataFrame(
np.random.randn(200,3),
columns=['a','b','c']
)
chart=alt.Chart(df).mark_circle().encode(
x='a',y='b',size='c',color='c')
st.altair_chart(c, width=-1)

streamlit.altair_chart(
altair_chart,
use_container_width = False
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# 折线图
chart_data = pd.DataFrame(
np.random.randn(20, 3),
columns=['a', 'b', 'c'])

st.line_chart(chart_data,
width=0, # 图表宽度,若为 0,自动选择宽度
height=0,
use_container_width=True) # 若为 True,图表宽度设置为列宽


# 面积图
st.area_chart(
data=None,
width=0,
height=0,
use_container_width=True
)
# 条形图
streamlit.bar_chart(
data=None,
width=0,
height=0,
use_container_width=True
)

# 散点图、地图
map_data = pd.DataFrame(
np.random.randn(1000, 2) / [50, 50] + [37.76, -122.4],
columns=['lat', 'lon'])

st.map(map_data)

# matplotlib.pyplot 图
st.pyplot()

# altair
st.altair_chart(my_altair_chart)

# Vega-Lite 图表
st.vega_lite_chart(data = None,spec = None,use_container_width = False,** kwargs)
# Plotly
st.plotly_chart(...)
# bokeh
st.bokeh_chart()
# pyDeck,3D 地图,点云
st.pydeck_chart(pydeck_obj = None,use_container_width = False)


# dagre-d3
st.graphviz_chart(fig_or_dot,use_container_width = False

交互控件

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# 按钮 button
if st.button('Say Hello'):
pass
st.button(
lablel:str,
key:Union[str,int,NoneType]=None, # 小部件的唯一键
help:Optional[str]=None, # 悬停时的工具提示
on_click:Optional[Callable[...,NoneType]]=None, # 单击时的可选回调
args:tuple=None, # 传道给回调函数的可选参数元组
kwargs:dict=None, # 传递给回调函数的可选字典
)

# 下载按钮
st.download_button("文件名",file)
st.download_button(
label: str,
data: Union[str,bytes,TextIO,BinaryIO] # 要下载的文件的内容
file_name: Optional[str], # 下载的文件的名称,如“test.py",若未指定则自动生成
mime: Optional[Str], # 数据的MIME类型,默认为 text/plain 或 application/octet-stream
key,
help: Optional[str],
on_click: Optional[Callable[...,NoneType]],
args,
kwargs,
)
# 将字符串下载为文件
text_contents = '''This is some text'''
st.download_button('Download some text', text_contents)

# 复选框 checkbox
checkbox_rst = st.checkbox('打开**', # 文本描述
value=False, # 选中状态
key=None, # 组件 ID,表示该组件的唯一性,若没有则会基于其内容来生成
help,
on_change, # 复选框值改变时的可选回调
args,
kwargs)
# 单选按钮 radio
st.radio(label, # 文本描述字符串
options, # 选项:list,tuple,numpy.ndarray,pandas.Series
index = 0, # int,预选索引
format_func=<class 'str'>, # 选项文本的显示格式化函数
key = None, # 组件 ID
help,
on_change,
args,
kwargs)

# 选择框 selectbox
option = st.selectbox(
'功能选择', # label,标签说明
('aa', 'bb', 'cc'), # list, tuple, np.ndarray,pd.Series,pd,DataFrame(选择第一列),对 streamlit 来说,会转为 str
index=0, # 预选索引
format_func=<class 'str'>,
key=None, # 标识组件的唯一键
help,
on_change,
args,
kwargs
)

# 多选 multiselect
st.multiselect(label, # str,文本描述
options, # 选项
default=None, # 默认选项
format_fumc=<class 'str'>,
key=None)


# 滑块 slider
rst=st.slider('alpha',min_value=0.0,max_value=5.0,value=0.0,step=0.1)
slider_rst=streamlit.slider(label, # str,文本描述
min_value=None, # 最小值,默认 0、0.0、time.min
max_value=None, # 最大值,默认 100、1.0、time.max
value=None, # 当前值,可取一个范围,如(2,5)
step=None, # 步长,1 或 0.01
format=None, # 数字显示格式化字符串
key=None)

# 选择滑块 select_slider
st.select_slider(
label, # 标签说明
options=[], #
value=None,
format_func=<class 'str'>,
key=None
)

# 时间滑块
from datetime import time
appointment = st.slider(
"选择时间区域",
value=(time(11, 30), time(12, 45)))
st.write("预约的时间为:", appointment)

# 日期时间滑块
from datetime import datetime
start_time = st.slider(
"When do you start?",
value=datetime(2020, 1, 1, 9, 30),
format="MM/DD/YY - hh:mm")
st.write("Start time:", start_time)


# 文本输入框 text_input
input_text = st.text_input('文本输入','')
st.text_input(
label,
value='', # 初始值
max_chars=None, # 最大字符长度
key=None,
type='default', # password or default
help,
autocomplete:str,
on_change,
args,
kwargs,
)

# 数字输入框
num=st.number_input('test', min_value=0.0,max_value=1.0,value=-1.0,step=0.01)
num=st.number_input('test', min_value=0,max_value=100,value=60,step=0.1)
num=st.number_input(label, # str,文本描述
min_value=None, # 允许的最小值,int/float/None
max_value=None, # 允许的最大值,int/float/None
value=<streamlit.DeltaGenerator.NoValue object>,
step=None, # 数值变化步长,默认 1 或 0.01
format=None)# 数值显示格式化字符串或 None

# 多行文本输入 text_area
streamlit.text_area(
label,
value = '',
height = None,
max_chars = None,
key = None
)

# 日期输入 date_input
st.date_input(
'选择日期',
value=None,
min_value=None, # datetime.date(2019, 7, 6)或 datetime.datetime()
max_value=None,
key=None)

# 时间输入 time_input
streamlit.time_input(
label,
value=None,
key=None)
t = st.time_input('Set an alarm for', datetime.time(8, 45))

# 文件上传,file_uploader
# BytesIO 的子类
uploaded_file = st.file_uploader( # 返回 None 或 UploadedFile 或 UploadedFile 列表
label, # "Choose a CSV file",
type=None, # str or list(str)文件类别,如['png','jpg']
accept_multiple_files = False# 允许同时上传多个文件
key = None)

# type(uploaded_file) # <class 'streamlit.uploaded_file_manager.UploadedFile'>
type(uploaded_file.getvalue()) # <class 'bytes'>

# file_update的图像读入
bg_image = st.sidebar.file_uploader("背景图像:", type=["png", "jpg"])
img_cv2 = cv2.imdecode(np.frombuffer(bg_image.getvalue(), np.uint8), 1)

# 设置限制大小
streamlit run your_script.py --server.maxUploadSize=1024

# 颜色选择 color_picker
color = st.colo_picker(
lable, # 'Pick A Color'
value=None, # 预选颜色,如'#00f900',None 则为黑色
key=None
)

媒体

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
# numpy_array, audio_bytes, file

# 图片
st.image(
r'D:/AlexNet.png', # str 图像路径,numpy.ndarray,BytesIO,或上述之一的列表
captioin=None, # 图像标题,对于多幅图像应为字符串列表
width=None, # 图像宽度,None 使用自身宽度
use_column_width=False, # 如果设置为 True,则使用列宽作为图像宽度
clamp=False, # 是否将图像的像素值压缩到有效域(0~255) ,仅对字节数组图像有效。
channels='RGB', # 图像通道类型,'RGB' 或 'BGR',默认值:RGB
output_format='PNG') # 图像格式:'JPEG' 或'PNG',默认值:JPEG

# 音频
audio_file = open('myaudio.ogg', 'rb')
audio_bytes = audio_file.read()
st.audio(data=audio_bytes, # url 路径,字节码流,BytesIO,numpy.ndarray,打开的文件
format='audio/ogg', # audio/wav
start_time=0)

# 视频
video_file=open(r'test.mp4','rb')
video_bytes=video_file.read()
st.video(
data=video_bytes, # URL 字符串,字节码流,BytesIO,Numpy.ndarray,打开的文件
format='video/mp4', # 视频文件的 MIME 类型,默认值:video/mp4
start_time=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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# 侧边栏
option = st.sidebar.selectbox(
'Which number do you like best?',
df['first column'])
st.sidebar.markdown()
st.sidebar.slider() # 侧边栏滑块
st.sidebar.line_chart()

# 多列
# 当前无法将列放在另一列中
st.columns(
spec # int:均匀划分的列数;list:[3,1,2] 按比列划分
)

st_column1, st_column2 = st.columns(2)
with st_column1:
pass
with st_column2:
pass

# 扩展器
with st.expander('隐藏内容'):
st.write('test')


# 隐藏内容
st.beat_expander(label=None,
expanded=False) # 默认是否展开
expander = st.beta_expander("FAQ")
expander.write("Here you could put in some really, really long explanations...")
with st.beta_expander("See explanation"):
st.write("""
test
""")


# 容器:多元素容器
c=st.container()
st.write('test')
c.write('test')
c.write('test')
# 容器:可容纳多个元素,可无序插入元素
container=st.beta_container()
container.write("This is inside the container")
st.write("This is outside the container")
container.write("This is inside too")
# to hold multiple elements,but,还没发现有啥用
with st.beta_container():
st.write("This is inside the container")
# You can call any Streamlit command, including custom components:
st.bar_chart(np.random.randn(50, 3))
st.write("This is outside the container")


# 容器:单元素占位符
my_slot1 = st.empty()
my_slot2 = st.empty()

st.text('This will appear last')
my_slot1.text('This will appear second')
my_slot2.line_chart(np.random.randn(20, 2))


import time
with st.empty():
for seconds in range(60):
st.write(f"⏳ {seconds} seconds have passed")
time.sleep(1)
st.write("✔️ 1 minute over!")

进度与状态

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# 实时显示状态
st.progress(value) # value,百分比,范围[0,100] 或[0.0,1.0]

my_bar=st.progress(0)

# 在执行代码块时临时显示一条消息
with st.spinner('waiting'):
for percent_complete in range(100):
st.spinner(text='正在计算中...')
time.sleep(0.05)
my_bar.progress(percent_complete+1)


# 庆祝气球
st.balloons()
# 信息框
st.info('This is an info')
# 警告框
st.warning('This is an warning')
# 错误框
st.error('This is an error')
# 成功框
st.success('Done!')
# 异常输出
e = RuntimeError('This is an exception of type RuntimeError')
st.exception(e) # 显示异常

# 结合占位符就是动画
# 初始化
progress_bar = st.progress(0)
status_text = st.empty()
chart = st.line_chart(np.random.randn(10, 2))

for i in range(100):
# 更新进度条
progress_bar.progress(i + 1)
new_rows = np.random.randn(10, 2)

# 更新文字说明
status_text.text(
'The latest random number is: %s' % new_rows[-1, 1])

# 添加新数据
chart.add_rows(new_rows)

# 为更新保留时间
time.sleep(0.1)

status_text.text('Done!')
st.balloons()


import numpy as np
import time

# Get some data.
data = np.random.randn(10, 2)

# Show the data as a chart.
chart = st.line_chart(data)

# Wait 1 second, so the change is clearer.
time.sleep(1)

# Grab some more data.
data2 = np.random.randn(10, 2)

# Append the new data to the existing chart.
chart.add_rows(data2)



控制流 - 表单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 后面的语句将不会运行,常在 st.warning('...')后使用
st.stop()

# 表单:将元素与提交按钮一起批处理
# 将一批元素一起指交,需与 st.form_submit_button结合使用,里面不能使用st.button
st.form(key:str, #
clear_on_submit:bool=False) # 提交时是否重置到默认值

# 点击时,提交form表单
st.form_submit_button(label:str="Submit",
help:Optional[str]=None,
on_click,args,kwargs)

with st.form('my_form'):
st.write("Inside the form")
slider_val = st.slider("Form slider")
checkbox_val = st.checkbox("Form checkbox")

# Every form must have a submit button.
submitted = st.form_submit_button("Submit")
if submitted:
st.write("slider", slider_val, "checkbox", checkbox_val)

源代码

1
2
3
4
5
6
7
# 在运行的上方输出其源代码
with st.echo():
st.write('test')

# 帮助
st.help(st.write)
st.help(pd.DataFrame)

性能

cache_data

如果这是 Streamlit 第一次看到这些参数值和函数代码,它将运行函数并将返回值存储在缓存中。下次使用相同的参数和代码调用函数时(例如,当用户与应用程序交互时),Streamlit 将完全跳过执行函数并返回缓存的值。在开发过程中,缓存会随着函数代码的更改而自动更新,从而确保最新的更改反映在缓存中。

如前所述,有两个缓存装饰器:

  • st.cache_data 是缓存返回数据的计算的推荐方法:从 CSV 加载数据帧、转换 NumPy 数组、查询 API 或任何其他返回可序列化数据对象(str、int、float、DataFrame、array、list 等)的函数。它在每次函数调用时都会创建数据的新副本,使其免受 突变和竞争条件 的影响。在大多数情况下,的行为是您想要的 - 所以如果您不确定,请从开始,看看它是否有效!st.cache_data``st.cache_data
  • st.cache_resource 是缓存全局资源(如 ML 模型或数据库连接)的推荐方法 - 您不想多次加载的不可序列化对象。使用它,您可以在应用的所有重新运行和会话之间共享这些资源,而无需复制或复制。请注意,对缓存返回值的任何更改都会直接改变缓存中的对象(更多详细信息见下文)。

缓存 -cache

  • 缓存可让 Streamlit 避免重复请求数据或重复计算,用于快速热更新服务,使用装饰器声明来实现。
  • 缓存会在第一次执行该函数时将结果存入缓存,若第二次被调用时以下三项未改变,会直接从缓存中取结果
    • 函数的输入参数
    • 函数依赖的外部变量、代码(函数)、文件等
    • 功能主体(构成函数主体的实际字节码)、输出
  • 目前还存在一定的局限,如:
    • 只检查当前工作目录的更改,若调用的第三方库改了代码,不会有反应。
    • 如果函数接收的数据是个实时返回的接口,例如股票,天气这类数据,那么 Streamlit 的缓存机制是不知道你的数据是否发生了变化
    • 另外,不要去更改缓存函数的输出,因为缓存的值是按引用存储的。
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
@st.cache(persist=True)
def load_data(arg1, arg2):
# Do something really slow in here!
return the_output

st.cache(pd.read_csv)

@st.cache
def load_data():
data=...
return data

# 传递数据库连接,连接对象重用
@st.cache(allow_output_mutation=True)
def get_database_connection():
return db.get_connection()

st.cache(
func=None, # 缓存功能
persist=False, # 是否缓存到磁盘
allow_output_mutation=False, # 是否允许返回值改变时不警告
shou_spinner=True, # 未命中时是否显示微调框
suppress_st_warning=Fasle, #
hash_funcs=None,
max_entries=None, # 保留在 cache 中的最大数量
ttl=None, # 保留在缓存中的最大秒数
)

# 代码清除缓存
st.cacheing.clear_cache()

experimental_memo

用于记忆函数执行的实验性函数装饰器

  • 返回计算的数据帧(pandas、numpy)、缓存下载的数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#  用于记忆大型数据
@st.experimental_memo
def fetch_and_clean_data(url):
return data


st.memo(
func: Optional[function] = None,
persist: Optional[str] = None, # 保存,唯一有效的值是:disk
show_spinner: bool = True, # 当cache miss时是否显示spinner
suppress_st_warning=False,
max_entries: Optional[int] = None, # 最大数目的项目保存数,或无穷大(设定了值,新条目添中时大开该值时老条目会删除)
ttl: Optional[float] = None)

st.experimental_memo.clear()

experimental_singleton

用于存储单例对象的实验函数装饰器

  • 通过引用返回项目,可返回任何对象类型。
  • 用于 Pytorch 加载的模型、数据库连接
  • 连接到应用程序的每个用户都可以同时使用单例对象,有必要确保 st.singleton 对象是线程安全的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
st.singleton(
func: Optional[function] = None,
show_spinner: bool = True,
suppress_st_warning=False)

# 用于存储单例对象的实验性函数装饰器:非数据对象
@st.experimental_singleton
def get_database_session(url):

from sqlalchemy.orm import sessionmaker

@st.singleton
def get_db_sessionmaker():
# This is for illustration purposes only
DB_URL = "your-db-url"
engine = create_engine(DB_URL)
return sessionmaker(engine)

dbsm = get_db_sessionmaker()
st.experimental_singleton.clear()

组合技

文件下载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# but,st.markdown 有最大 50MB 的限制
import streamlit as st
import os
import base64

def get_file_download(file_path,file_label='File'):
with open(file_path,'rb') as f:
file_data=f.read()
st.text(1)
base64_bin_str=base64.b64encode(file_data).decode()
st.text(2)
href = f'<a href="data:application/octet-stream;base64,{base64_bin_str}" download="{os.path.basename(file_path)}">下载<b>【{file_label}】</b></a>'
st.text(3)
return href
html=get_file_download('/mnt/data/model_api_img/archieve/日志打包/等径 _ 上层 _2021-01-13.zip', 'schedular_job.py')
st.text(4)

st.markdown(html, unsafe_allow_html=True)
# st.markdown(get_binary_file_downloader_html('data.csv', 'My Data'), unsafe_allow_html=True)
# st.markdown(get_binary_file_downloader_html('2g1c.mp4', 'Video'), unsafe_allow_html=True)

# 最终选择
python -m http.server 8502 --directory /app/storage/ &
streamlit run app.py

按钮显示不同页面

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 streamlit as st
import pandas as pd

st.title("按钮对应不同页面")

col1, left, col2, right, col3 = st.beta_columns([1, 0.1, 1, 0.1, 1])

with col1:
page1 = st.button("显示图表")

with col2:
page2 = st.button("查看图像")

with col3:
page3 = st.button("输出文字")

if page1:
table = pd.DataFrame([[4, 5, 6], [1, 2, 3]], columns=["a", "b", "c"])
st.line_chart(table)

if page2:
st.image("test.jpg")

if page3:
st.subheader("新页面")
st.subheader("测试页面")

打包成 exe

遇到的问题

  • 问题:AttributeError: module ‘plotly.graph_objs.layout.template.data’ has no attribute ‘Icicle’
  • 解决方案:安装 5.+ 版本的 pandas
1
2
AttributeError: module 'google.protobuf.descriptor' has no attribute '_internal_create_key'
pip install --upgrade protobuf
  1. st.markdown 会将路径中的下划线解释为语法
1
st.markdown('./test/__aa__.py') # aa 会加粗,不过这不是 bug
  1. 出现 AttributeError: module ‘typing‘ has no attribute ‘_ClassVar‘错误
1
pip uninstall dataclasses
PermissionError: [Errno 13] Permission denied: ‘/root/.streamlit’

主要原因在于启动时使用了错误的权限

  • 问题:failed to process a websocket message(RangeError:index out of range: 58+ 10>58)
  • 解决方案:因为多个交互或多个运行在打架,重启程序试试

  • 问题:

streamlit-pages

streamlit-pages:用于方便的制作 st 的多页效果

1
pip install streamlit-pages
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
import streamlit as st
from streamlit_pages.streamlit_pages import MultiPage

def home():
st.write("Welcome to home page")
if st.button("Click Home"):
st.write("Welcome to home page")


def about():
st.write("Welcome to about page")
if st.button("Click about"):
st.write("Welcome to About page")


def contact():
st.write("Welcome to contact page")
if st.button("Click Contact"):
st.write("Welcome to contact page")


# call app class object
app = MultiPage()
# Add pages
app.add_page("Home",home)
app.add_page("About",about)
app.add_page("Contact",contact)
app.run()

pyecharts

pyecharts:基于百度开源的数据可视化工具库 echarts。原 js 的 Python 接口。适合数据工程 demo 展示

  • 好用 + 好看:API语法简单,效果出众,基于 canvas 与 WebGL,高度定制图表类型与动态效果。
  • 3D 图表、地图、日历、微信小程序版本等 30+ 的常用图表
    • 400+ 的地图文件 + 原生的百度地图,地理数据可视化
  • 轻松集成到 web 框架
  • 文档详细
  • 简洁的 API 设计,使用如丝滑般流畅,支持链式调用
  • 囊括了 30+ 种常见图表,应有尽有
  • 支持主流 Notebook 环境,Jupyter Notebook 和 JupyterLab
  • 可轻松集成至 Flask,Sanic,Django 等主流 Web 框架
  • 高度灵活的配置项,可轻松搭配出精美的图表
  • 详细的文档和示例,帮助开发者更快的上手项目
  • 多达 400+ 地图文件,并且支持原生百度地图,为地理数据可视化提供强有力的支持
    Pyecharts 是我国开发人员开发的,相比较 Matplotlib、Seaborn 等可视化库,Pyecharts 十分符合国内用户的使用习惯。

Pyecharts 的目的是实现 Echarts 与 Python 的对接,以便在 Python 中使用 Echarts 生成图表。

Echarts 是百度开源的一个数据可视化 JavaScript 库,生成的图的可视化效果非常好,其凭借良好的交互性,精巧的图表设计,得到了众多开发者的认可

特点

  • 词云、地图等

配置

1
2
3
4
5
6
7
8
9
10
pip install pyecharts
pip install pyecharts_snapshot # 用于导出为图片

#地图包
pip install echarts-countries-pypkg
pip install echarts-china-provinces-pypkg
pip install echarts-china-cities-pypkg
pip install echarts-china-counties-pypkg
pip install echarts-china-misc-pypkg
pip install echarts-united-kingdom-pypkg

主题

1
2
from pyecharts.globals import ThemeType
bar=Bar(init_opts=opts.InitOpts(theme=ThemeType.LIGHT))
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
from pyecharts.charts import Bar
from pyecharts import options as opts
from pyecharts.render import make_snapshot
from pyecharts.faker import Collector, Faker
from pyecharts.charts import Bar
from pyecharts import options as opts
from pyecharts.render import make_snapshot
from snapshot_selenium import snapshot
bar = Bar()
bar.add_xaxis(["男", "女"])
bar.add_yaxis("人数", [100, 200])
bar.set_global_opts(title_opts=opts.TitleOpts(title="男女人数", subtitle="不知道写啥的副标题"))
bar.render("test.html")
make_snapshot(snapshot, bar.render(), "bar.png")
# import pyecharts
# from pyecharts import Bar
# bar =Bar("我的第一个图表", "这里是副标题")
# bar.add("服装", ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"], [5, 20, 36, 10, 75, 90])bar.show_config()bar.render()
# import math
# for x
# line =Line("像素点-灰度值")
# line.add("灰度修士", attr, v1, is_fill=True, line_opacity=0.2, area_opacity=0.4, symbol=None)
# line.show_config()
# line.render()
# from pyecharts import Line
# line = Line("折线图","一年的降水量与蒸发量",title_top="45%")
# colmns=list(range(0,20))
# data=[]
# for x in colmns:
# data.append((255/2)*math.atan(x-20)+(255/2))
# line.add("降水量", columns, data1, is_label_show=True)
# line.add("蒸发量", columns, data2, is_label_show=True)
# grid = Grid()
# grid.render()
# from pyecharts import Line
# x = ['2018-{:0>2d}'.format(s) for s in range(1,13)]
# y1 = [5,10,26,30,35,30,20,26,40,46,40,50]
# y2 = [8,20,24,36,40,36,40,45,50,53,48,58]
# line = Line(title = "月销售总额",width = 600,height = 420)
# line.add(name = "商家 A", x_axis = x, y_axis = y1,
# line_width = 3,line_color = 'red')
# line.add(name = "商家 B", x_axis = x, y_axis = y2,
# yaxis_min = 0,yaxis_max = 100,is_xaxis_boundarygap = False,
# is_datazoom_show =True,line_width = 2,line_color = 'cyan')
# line.render('折线图示范.html')
# line
1
2
3
4
5
6
7
8
9
from pyecharts.charts import Bar
from pyecharts.charts import Line
from pyecharts import options as opts
from pyecharts.charts import EffectScatter
from pyecharts.globals import SymbolType
from pyecharts.charts import Grid
from pyecharts.charts import WordCloud
from pyecharts.charts import Map
import random
1
2
3
4
5
6
7
8
from pyecharts import Bar
bar = Bar("我的第一个图表", "这里是副标题")
bar.add("服装", ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"], [5, 20, 36, 10, 75, 90])
#add 添加数据与设置
bar.show_config()
#show_config 打印图表的所有配置
bar.render()
#生成一个 html 文件,支持 path

折线图

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

import pyecharts.options as opts
from pyecharts.charts import Line

"""
Gallery 使用 pyecharts 1.1.0
参考地址: https://www.echartsjs.com/examples/editor.html?c=line-marker

目前无法实现的功能:

1、最低气温的最高值暂时无法和 Echarts 的示例完全复刻
"""

week_name_list = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]
high_temperature = [11, 11, 15, 13, 12, 13, 10]
low_temperature = [1, -2, 2, 5, 3, 2, 0]
a = (
Line(init_opts=opts.InitOpts(width="1600px", height="800px"))
.add_xaxis(xaxis_data=week_name_list)
.add_yaxis(
series_name="最高气温",
y_axis=high_temperature,
markpoint_opts=opts.MarkPointOpts(
data=[
opts.MarkPointItem(type_="max", name="最大值"),
opts.MarkPointItem(type_="min", name="最小值"),
]
),
markline_opts=opts.MarkLineOpts(data=[opts.MarkLineItem(type_="average", name="平均值")]),
)
.add_yaxis(
series_name="最低气温",
y_axis=low_temperature,
markpoint_opts=opts.MarkPointOpts(data=[opts.MarkPointItem(value=-2, name="周最低", x=1, y=-1.5)]),
markline_opts=opts.MarkLineOpts(
data=[
opts.MarkLineItem(type_="average", name="平均值"),
opts.MarkLineItem(symbol="none", x="90%", y="max"),
opts.MarkLineItem(symbol="circle", type_="max", name="最高点"),
]
),
)
.set_global_opts(
title_opts=opts.TitleOpts(title="未来一周气温变化", subtitle="纯属虚构"),
tooltip_opts=opts.TooltipOpts(trigger="axis"),
toolbox_opts=opts.ToolboxOpts(is_show=True),
xaxis_opts=opts.AxisOpts(type_="category", boundary_gap=False),
)
.render("temperature_change_line_chart.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
32
33
34
35

from pyecharts import options as opts
from pyecharts.charts import Bar
from pyecharts.faker import Faker

print(Faker.choose())
print(Faker.values())
print(Faker.values())
NUM_START = 1
NUM_END = 120
NUM_LIST = [str(i) for i in range(NUM_START, NUM_END + 1)]

c = (
Bar()
.add_xaxis(NUM_LIST)
.add_yaxis("衣服", Faker.values(), stack="stack1", is_large=True)
.add_yaxis("裤子", Faker.values(), stack="stack1", is_large=True)
.add_yaxis("鞋子", Faker.values(), stack="stack1", is_large=True)
.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
.set_global_opts(
title_opts=opts.TitleOpts(title="数量"),
datazoom_opts=opts.ToolBoxFeatureDataZoomOpts(
is_show=True, # 提示语,
zoom_title="区域缩放",
back_title="区域缩放还原",
zoom_icon=None,
back_icon=None,
xaxis_index=None,
yaxis_index=None,
filter_mode="filter",
),
)
.render('test.html')
)

地图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from pyecharts import options as opts
from pyecharts.charts import Map
import random

province = ['广东', '湖北', '湖南', '四川', '重庆', '黑龙江', '浙江', '山西', '河北', '安徽', '河南', '山东', '西藏']
data = [(i, random.randint(50, 150)) for i in province]
_map = (
Map()
.add("销售客", data, "china")
.set_global_opts(
title_opts=opts.TitleOpts(title="Map-基本示例"),
legend_opts=opts.LegendOpts(is_show=False),
visualmap_opts=opts.VisualMapOpts(max_=200, is_piecewise=True),
)
)

_map.render("test.html")

streamlit-echarts

streamlit-echarts:两大神器的合体

1
pip install streamlit-echarts

基本使用

1
2
3
4
5
6
7
8
9
st_echarts(
options: Dict
theme: Union[str, Dict]
events: Dict[str, str]
height: str
width: str
renderer: str
key: str
)
1
2
3
4
5
6
7
8
9
10
11
12
13
from streamlit_echarts import st_echarts

options = {
"xAxis": {
"type": "category",
"data": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
},
"yAxis": {"type": "value"},
"series": [
{"data": [820, 932, 901, 934, 1290, 1330, 1320], "type": "line"}
],
}
st_echarts(options=options)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from pyecharts import options as opts
from pyecharts.charts import Bar
from streamlit_echarts import st_pyecharts

b = (
Bar()
.add_xaxis(["Microsoft", "Amazon", "IBM", "Oracle", "Google", "Alibaba"])
.add_yaxis(
"2017-2018 Revenue in (billion $)", [21.2, 20.4, 10.3, 6.08, 4, 2.2]
)
.set_global_opts(
title_opts=opts.TitleOpts(
title="Top cloud providers 2018", subtitle="2017-2018 Revenue"
),
toolbox_opts=opts.ToolboxOpts(),
)
)
st_pyecharts(b)

streamlit-aggrid

streamlit-aggrid:增强的表格

streamlit-ace

streamlit-ace:增强的编辑器

1
pip install streamlit-ace
1
2
3
4
5
6
7
8
9
import streamlit as st

from streamlit_ace import st_ace

# Spawn a new Ace editor
content = st_ace()

# Display editor's content as you type
content

streamlit-image-comparison

streamlit-image-comparison:图像比较

1
pip install streamlit-image-comparison
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Streamlit Image-Comparison Component Example

import streamlit as st
from streamlit_image_comparison import image_comparison

# set page config
st.set_page_config(page_title="Image-Comparison Example", layout="centered")

# render image-comparison

image_comparison(
img1="image1.jpg",
img2="image2.jpg",
label1="text1",
label2="text1",
width=700,
starting_position=50,
show_labels=True,
make_responsive=True,
in_memory=True,
)

streamlit-chat

st-chat:Chat-bot UI

1
pip install streamlit-chat
1
2
3
4
5
import streamlit as st
from streamlit_chat import message

message("My message")
message("Hello bot!", is_user=True) # align's the message to the right

streamlit-lottie

Streamlit-lottie:Streamlit 中运行动画效果

Altair

Altair:让数据科学家更多地关注数据本身和其内在联系的库

  • 参考文档:官方文档
  • 特点:
    • 上手快、接口简单、使用优雅
    • 基于 Vega 和 Vega-Lite,
  • 流程:
    • 准备数据
      • pd.DataFrame:优先使用
      • altair.Data:altair 自己的数据对象
      • 指向 json 或 csv 格式文件的 url:即可获取网上的在线数据
      • 一个支持 geo_interface 接口的对象,如 Geopandas.GeoDataFrame
    • 使用数据创建图表:
    • 设置图表类型:折线图、散点图还是什么图
    • 对图像进行编码:什么轴显示什么数据
  • 三大思想
    • data: 数据,数据集
    • mark: 标记,表示数据点的形状,如实心点、空心点、方块等
    • encode: 编码
      • x:x 轴数值
      • y:y 轴数值
      • color:标记点颜色
      • opacity:标记点的透明度
      • shape:标记点的形状
      • size:标记点的大小
      • row:按行分列图片
      • column:按列分列图片

基本使用

1
pip install altair vega_datasets
1
2
3
4
5
6
import altair as alt

chart=alt.Chart(cars)
alt.Chart(data).mark_point().encode(encoding_1='column_1',encoding_2='column_2')
# 需联网才能用,有 web 上的 js
chart.save('test.html')
1
2
3
4
5
6
7
8
9
10
11
df_data=pd.DataFrame({
'name':['zhang','li','cheng','wang'],
'age':[20,12,18,30]
})
# 条形图
chart=alt.Chart(df_data).mark_bar().encode(
x='name',
y='age'
)

# 热力图

matplotlib

matplotlib:2D 绘图库,Python 可视化最基本、最常用的库。偏向学术(不够好看),但大家用得多,得会基本操作

1
2
3
4
5
6
7
8
import matplotlib.pyplot as plt
x = [1, 2, 3, 4, 5, 6, 7]
y = [50, 51, 52, 48, 47, 49, 46]
plt.xlabel('day')
plt.ylabel('>>')
plt.title('what')
plt.plot(x, y, color='green', linewidth=5, linestyle='dotted')
plt.show()
1
2
plt.imshow() # 对图像进行处理
plt.show() # 此时才会将处理后的图像显示出来
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import matplotlib.pyplot as plt
import numpy as np

x=np.linspace(-3,3,50)
y1=2*x+1
y2=x**2
# plt.figure() #一个 figure 就是一个图
# plt.plot(x,y1)

plt.figure(num=3,figsize=(8,5))
plt.plot(x,y2)
plt.plot(x,y1,color='red',linewidth=1.0,linestyle='--')
plt.xlim((-1.2))#限制
plt.ylim((-2,3))
plt.xlabel('i am x ')#坐标轴描述
plt.ylabel('i am y')

new_ticks =np.linspace(-1,2,5)
print(new_ticks)
plt.xticks(new_ticks)
plt.yticks([-2,-1.8,-1,1.22,3,],
['good','bad','ok','justsoso','?'])
plt.show()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 折线图
from matplotlib import pyplot as plt

x = range(1, 7)
y = [13, 15, 14, 16, 15, 17]
'''
figsize:设置图片的宽、高,单位为英寸
dpi:设置分辨率
'''
plt.figure(figsize=(8, 5), dpi=80)
plt.title('折线图')
plt.xlabel('x 轴')
plt.ylabel('y 轴')
'''
color:颜色
linewidth:线的宽度
marker:折点样式
linestyle:线的样式,主要包括:'-'、'--'、'-.'、':'
'''
plt.plot(x, y, color='red', marker='o', linewidth='1', linestyle='--')
# 保存
# plt.savefig('test.png')
plt.show()

中文字体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import numpy as np
from matplotlib import pyplot as plt
from matplotlib.font_manager import FontProperties
import matplotlib.pyplot as plt

font = FontProperties(fname='/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc', size=20)
plt.title('测试', fontproperties=font)


x = np.linspace(-6, 6, 1024)
y = np.sinc(x)
plt.plot(x, y)
plt.savefig('sinc.png', c='c')

配置

matplotlib 中文
在 shell 的配置中重新设置配置变量(bash的话设置文件 .bashrczsh则设置文件 .zshrc)。方法是末尾添加:

1
export PYTHONIOENCODING="utf8"
1
2
import matplotlib as mpl
import matplotlib.pyplot as plt

中文显示问题

  • 方法一
1
2
from pylab import mpl
mpl.rcParams['font.sans-serif'] = ['SimHei'] #中文显示问题
  • 方法二
    • 删除原本 Matplotlib 字体的缓存
    • 在 terminal 中使用以下命令(不同 Python 版本 cache 会有些不同)
1
rm ~/.matplotlib/fontList.py3k.cache
  • 重启(restart)Jupiter Notebook,并指定 Matplotlib 使用我们安装的字体
1
2
import matplotlib.pyplot as plt
plt.rc('font', family='Microsoft YaHei')

dash

dash:开发 web 应用的高生产率工具率,基于 Flask、Plotly.js 与 React.js,不需懂 javascript 就能作出好看的 UI 元素

1
2
3
4
pip install dash==0.29.0
pip install dash-html-components==0.13.2 #Dash 库的 HTML 组件
pip install dash-core-components==0.36.0 #Dash 库核心组件
pip install dash-table==3.1.3 #交互数据库表单(新)

wordcloud

wordcloud:以词云为对象,依据词语出现的频率绘制词云,可设定词云的大小、颜色、形状等

  • 词云图:文字云,对文本数据中出现频率较高的 关键词 在视觉上予以突出,形成关键词的渲染。
1
pip install wordcloud
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
32
background_color:输出的背景颜色
mask:array形式的轮廓图片,如果参数为空,则使用二维遮罩绘制词云
font_path:字体路径
max_words:词云图的最大词语数量
stopwords:停用词列表
font_step:字体字号的步进间隔,默认是1
font_path : string //字体路径,需要展现什么字体就把该字体路径+后缀名写上,如:font_path = '黑体.ttf'
width : int (default=400) //输出的画布宽度,默认为400像素
height : int (default=200) //输出的画布高度,默认为200像素
prefer_horizontal : float (default=0.90) //词语水平方向排版出现的频率,默认 0.9 (所以词语垂直方向排版出现频率为 0.1
mask : nd-array or None (default=None) //如果参数为空,则使用二维遮罩绘制词云。如果 mask 非空,设置的宽高值将被忽略,遮罩形状被 mask 取代。除全白(#FFFFFF)的部分将不会绘制,其余部分会用于绘制词云。如:bg_pic = imread('读取一张图片.png'),背景图片的画布一定要设置为白色(#FFFFFF),然后显示的形状为不是白色的其他颜色。可以用ps工具将自己要显示的形状复制到一个纯白色的画布上再保存,就ok了。
scale : float (default=1) //按照比例进行放大画布,如设置为1.5,则长和宽都是原来画布的1.5倍。
min_font_size : int (default=4) //显示的最小的字体大小
font_step : int (default=1) //字体步长,如果步长大于1,会加快运算但是可能导致结果出现较大的误差。
max_words : number (default=200) //要显示的词的最大个数
stopwords : set of strings or None //设置需要屏蔽的词,如果为空,则使用内置的STOPWORDS
background_color : color value (default=”black”) //背景颜色,如background_color='white',背景颜色为白色。
max_font_size : int or None (default=None) //显示的最大的字体大小
mode : string (default=”RGB”) //当参数为“RGBA”并且background_color不为空时,背景为透明。
relative_scaling : float (default=.5) //词频和字体大小的关联性
color_func : callable, default=None //生成新颜色的函数,如果为空,则使用 self.color_func
regexp : string or None (optional) //使用正则表达式分隔输入的文本
collocations : bool, default=True //是否包括两个词的搭配
colormap : string or matplotlib colormap, default=”viridis” //给每个单词随机分配颜色,若指定color_func,则忽略该方法。
fit_words(frequencies) //根据词频生成词云
generate(text) //根据文本生成词云
generate_from_frequencies(frequencies[, ...]) //根据词频生成词云
generate_from_text(text) //根据文本生成词云
process_text(text) //将长文本分词并去除屏蔽词(此处指英语,中文分词还是需要自己用别的库先行实现,使用上面的 fit_words(frequencies) )
recolor([random_state, color_func, colormap]) //对现有输出重新着色。重新上色会比重新生成整个词云快很多。
to_array() //转化为 numpy array
to_file(filename) //输出到文件
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
32
33
#预处理
import jieba
with open(..) as f:
text=f.read()
cut =jieba.cut(text) #分词
string=' '.join(cut) #空格连接
import wordcloud
w=wordcloud.WordCloud(background_color="white",height=200,width=200,min_font_size=5,max_font_size=20,font_step=1,font_path="",max_words=200,stop_words="你好 Chen")
w.generate("词语 你好") #空格分隔-统计频率-
w.to_file('picture.png')
import matplotlib.pyplot as plt
plt.imshow(w)
plt.axis("off")
plt.show()


def show(s):
# 创建 wordcloud 对象
wc = wordcloud.WordCloud(
# r'C:\windows\fonts\simfang.ttf',
width=500, height=400,
background_color='white',
font_step=3,
random_state=False,
prefer_horizontal=0.9)
# 创建并显示词云
t = wc.generate(s)
t.to_image().save('t.png')

# 如果空间足够,就全部显示
# 如果词太多,就按频率显示,频率越高的词越大
show('hello world 董付国 董付国 董付国 董付国 abc fgh yhnbgfd 董付国 董付国 董付国 董付国 Python great Python Python')

basemap

mapbox

mapbox:处理地理数据引擎更强的可视化工具库

Geoplotlib

Geoplotlib:地图可视化

pynimate

pynimate:绘制动态可视化图

  • 需要 Python3.9+?
  • 会使用 Barplot() 来创建条形数据动画,输入数据需要是 pandas 数据结构
1
2
3
4
5
6
7
8
9
10
11
12
13
import pandas as pd
df = pd.read_csv('data'csv').set_index('time')
df = pd.DataFrame(
{
"time": ["1960-01-01", "1961-01-01", "1962-01-01"],
"Afghanistan": [1, 2, 3],
"Angola": [2, 3, 4],
"Albania": [1, 2, 5],
"USA": [5, 3, 4],
"Argentina": [1, 4, 5],
}
).set_index("time")

给博主来一杯卡布奇诺