Streamlit学习笔记(1)

Streamlit 和 很多库是兼容的:

安装

$pip install streamlit

安装的包:

Installing collected packages: terminado, prometheus-client, argon2-cffi, Send2Trash, notebook, widgetsnbextension, ipywidgets, pydeck, astor, cachetools, protobuf, jmespath, botocore, base58, validators, toolz, altair, pyarrow, s3transfer, boto3, tzlocal, blinker, smmap, gitdb, gitpython, enum-compat, streamlit
Successfully installed Send2Trash-1.5.0 altair-4.1.0 argon2-cffi-20.1.0 astor-0.8.1 base58-2.0.1 blinker-1.4 boto3-1.16.21 botocore-1.19.21 cachetools-4.1.1 enum-compat-0.0.3 gitdb-4.0.5 gitpython-3.1.11 ipywidgets-7.5.1 jmespath-0.10.0 notebook-6.1.5 prometheus-client-0.9.0 protobuf-3.14.0 pyarrow-2.0.0 pydeck-0.5.0 s3transfer-0.3.3 smmap-3.0.4 streamlit-0.71.0 terminado-0.9.1 toolz-0.11.1 tzlocal-2.1 validators-0.18.1 widgetsnbextension-3.5.1

演示

$ streamlit hello

  👋 Welcome to Streamlit!

  If you're one of our development partners or you're interested in getting
  personal technical support or Streamlit updates, please enter your email
  address below. Otherwise, you may leave the field blank.

  Email: your_email

  Privacy Policy:
  As an open source project, we collect usage statistics. We cannot see and do
  not store information contained in Streamlit apps. You can find out more by
  reading our privacy policy at: https://streamlit.io/privacy-policy

  If you'd like to opt out of usage statistics, add the following to
  ~/.streamlit/config.toml, creating that file if necessary:

    [browser]
    gatherUsageStats = false


  Welcome to Streamlit. Check out our demo in your browser.

  Local URL: http://localhost:8501
  Network URL: http://192.168.31.193:8501

  Ready to create your own Python apps super quickly?
  Head over to https://docs.streamlit.io

配置

根据提示 gedit ~/.streamlit/config.toml , 插入如下内容:

# 禁止收集用户统计信息
[browser]
gatherUsageStats = false

# 热加载,端口
[server]
runOnSave = true
port=8501

[runner]
# 禁止掉 magic commands
magicEnabled = false

示例页: http://localhost:8501, 感觉几个示例很cool 😋

开发第一个app

参考这里

# first_app.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import streamlit as st
import numpy as np
import pandas as pd
st.title('第一个app')

直接执行如下命令就可以自动打开浏览器了:

streamlit run first_app.py

集成多个app

参考:Building Multi Page Web App Using Streamlit,该文章中称 app 为page容易让人误解。

记住Streamlit 本质上是一个顺序执行的 Python脚本程序, 在执行过程中当然可以像其他 Python程序一样调用任意其他 Python模块。

1. appMain.py:可以视为 streamlit 的入口脚本

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# refer to: https://medium.com/@u.praneel.nihar/building-multi-page-web-app-using-streamlit-7a40d55fa5b4
# appMain.py

import app1
import app2
import streamlit as st

# app列表,
appList = {
    "App1": app1,
    "App2": app2
}
st.sidebar.title('Navigation')
selection = st.sidebar.radio("Go to", list(appList.keys()))
appCurrent = appList[selection]
appCurrent.app()

2. app1.py 和 app2.py:被集成的脚本

app1,app2 可以视为 streamlit 顺序执行过程中被选择性调用的代码。

app1.py:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# app1.py
import streamlit as st
def app():
    st.title('APP1')
    st.write('Welcome to app1')

app2.py:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# app2.py
import streamlit as st
def app():
    st.title('APP2')
    st.write('Welcome to app2')
    selection = st.sidebar.radio("Go to", ['app2:Item1','app2:Item1'])

执行效果:

注意:app2 和 appMain 共用 sidebar

nginx 集成 streamlit

nginx端配置:

        server {
            location /streamlit {
                 proxy_pass       http://localhost:8501/;
                 proxy_http_version 1.1;
                 proxy_set_header Upgrade $http_upgrade;
                 proxy_set_header Connection "Upgrade";
                 proxy_set_header Host $host;
            }

需要同时部署对应的静态资源的部署, 静态资源目录在python包的类似如下位置: ~/lib/python3.8/site-packages/streamlit/static

Get started

示例1

涉及内容:

  • mardown支持: 文本输出,空行输出
  • 数值变量输出
  • 折线图,地图
  • magic commands:有时候会把一些注释显示出来,最好禁止掉
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import streamlit as st
import numpy as np
import pandas as pd

# markdown
st.write('# 1级标题')
st.write('## 2级标题')
st.write('### 3级标题')
st.write('~~删除线~~')
st.write('表格测试:')
st.write('''| Tables        | Are           | Cool  |
| ------------- |:-------------:| -----:|
| col 3 is      | right-aligned | $1600 |
| col 2 is      | centered      |   $12 |
| zebra stripes | are neat      |    $1 |

''')

# 插入空行
st.text('\n')

# st.write 可以接受很多数据直接输出

data_pd = pd.DataFrame({
    '第一列': [1, 2, 3, 4],
    '第二列': [10, 20, 30, 40]
})

# 输出表格:st.table 比较好用
st.write(data_pd)
st.text('\n')
st.dataframe(data_pd) 
st.text('\n')
st.table(data_pd)
st.text('\n')

# magic commands:直接列出变量显示,等同于调用了 st.write() 方法
data_pd

# 折线图
chart_data = pd.DataFrame(
     np.random.randn(20, 3),
     columns=['a', 'b', 'c'])
st.text('\n')
st.table(chart_data)

st.line_chart(chart_data)

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

st.text('\n')
st.table(map_data)
st.text('\n')

st.map(map_data)

示例2:添加交互类小部件widgets

参考 https://docs.streamlit.io/en/stable/getting_started.html

涉及内容:

  • 复选框,下拉选择框,左边栏,进度条
  • 一行显示多个小部件
  • 内容折叠显示
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import streamlit as st
import numpy as np
import pandas as pd
import time

# 使用复选框checkboxes显示隐藏数据
chart_data = pd.DataFrame(
       np.random.randn(20, 3),
       columns=['a', 'b', 'c'])

if st.checkbox('显示数据'):
    st.line_chart(chart_data)

# 下拉选择框,默认选中第一个
# 每次选中一个,整个脚本会重新跑一遍
df = pd.DataFrame({
  'first column': [1, 2, 3, 4],
  'second column': [10, 20, 30, 40]
})

option = st.selectbox(
    'Which number do you like best?',
     df['first column'],key='1')

'You selected: ', option

# 左边栏: sidebar
# 将小部件放入左边栏语法:st.sidebar.[element_name]()
# 需要使用key区分同一类别的不同小部件

option2 = st.sidebar.selectbox(
    'Which number do you like best?',
     df['first column'],key='2')

'You selected: ', option2

# 一行部署多个小部件
left_column, middle_column,right_column = st.beta_columns(3)
pressed = left_column.button('show right text')

if pressed:
    right_column.text("Woohoo!")
    middle_column.text("I'm here")

# 可扩展段落
expander = st.beta_expander("FAQ")
expander.text('''Here you could put in some really, really long explanations...
line2
line3
''')

# 显示进度, 用 time.sleep()模拟长时间的操作
st.sidebar.text('开始计算...')

# 显示占位符:文字和进度条
latest_iteration = st.sidebar.empty()
bar = st.sidebar.progress(0)

# 更新进度条内容
for i in range(100): 
  # Update the progress bar with each iteration.
  latest_iteration.text(f'Iteration {i+1}')
  bar.progress(i + 1)
  time.sleep(0.1)

st.sidebar.text('...and now we\'re done!')

效果:

创建一个数据探索APP:Create a data explorer app

涵盖的内容:

  • 数据加载,数据预处理,数据显示
  • 使用 @st.cache 标识函数
  • 使用 st.slider 滑动条过滤要显示的数据

附注释代码:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import streamlit as st
import numpy as np
import pandas as pd

st.title('纽约市的优步接客数据分析')

DATE_COLUMN = 'date/time'
DATA_URL = ('https://s3-us-west-2.amazonaws.com/streamlit-demo-data/uber-raw-data-sep14.csv.gz')
'''数据部分内容:日期/时间,纬度/经度 latitude,longitude
Date/Time   Lat Lon Base
9/1/2014 0:01:00    40.2201 -74.0021    B02512
9/1/2014 0:01:00    40.75   -74.0027    B02512
9/1/2014 0:03:00    40.7559 -73.9864    B02512
9/1/2014 0:06:00    40.745  -73.9889    B02512
9/1/2014 0:11:00    40.8145 -73.9444    B02512
9/1/2014 0:12:00    40.6735 -73.9918    B02512
9/1/2014 0:15:00    40.7471 -73.6472    B02512
9/1/2014 0:16:00    40.6613 -74.2691    B02512
'''

'''
  使用 @st.cache 标识函数后,如果不是第一次调用该函数,
  并且如下三项内容没有变化, 不会再执行该函数而是
  直接返回上次的执行结果

- 函数本身没有变化:The actual bytecode that makes up the body of the function
- 函数依赖没有变化:Code, variables, and files that the function depends on
- 函数参数没有变化:The input parameters that you called the function with
'''

@st.cache
def load_data(nrows):
    # 读取指定行数的数据
    data = pd.read_csv(DATA_URL, nrows=nrows)
    '''
        Date/Time      Lat      Lon    Base
0     9/1/2014 0:01:00  40.2201 -74.0021  B02512
1     9/1/2014 0:01:00  40.7500 -74.0027  B02512
2     9/1/2014 0:03:00  40.7559 -73.9864  B02512
'''
    # 行标题小写
    lowercase = lambda x: str(x).lower()
    data.rename(lowercase, axis='columns', inplace=True)
    '''
      date/time      lat      lon    base
0     9/1/2014 0:01:00  40.2201 -74.0021  B02512
1     9/1/2014 0:01:00  40.7500 -74.0027  B02512
2     9/1/2014 0:03:00  40.7559 -73.9864  B02512
3     9/1/2014 0:06:00  40.7450 -73.9889  B02512
'''
    #转换日期时间格式
    data[DATE_COLUMN] = pd.to_datetime(data[DATE_COLUMN])
    '''
              date/time      lat      lon    base
0   2014-09-01 00:01:00  40.2201 -74.0021  B02512
1   2014-09-01 00:01:00  40.7500 -74.0027  B02512
2   2014-09-01 00:03:00  40.7559 -73.9864  B02512
3   2014-09-01 00:06:00  40.7450 -73.9889  B02512
'''
    return data

# 将st.text 占位部件命名,方便改变显示内容
data_load_state = st.text('Loading data...')
data = load_data(10000)
# 根据数据cache加载状态更新该部件显示的内容
data_load_state.text("Done! (using st.cache)")


if st.checkbox('显示原始数据'):
    st.subheader('原始数据') # 标题
    st.write(data)

st.subheader('每小时接客数量')

# numpy.histogram()函数将输入数组和bin作为两个参数
# bin数组中的连续元素用作每个bin的边界
hist_values = np.histogram(data[DATE_COLUMN].dt.hour, bins=24, range=(0,24))[0]
# 直方图:st.bar_chart() 
st.bar_chart(hist_values)

# Some number in the range 0-23,默认值18
hour_to_filter = st.slider('hour', 0, 23, 18)
filtered_data = data[data[DATE_COLUMN].dt.hour == hour_to_filter]

st.subheader('%s:00 接客数量地图' % hour_to_filter)
st.map(filtered_data)

组件开发 Create a Streamlit Component

可以使用 JavaScript 和 HTML 开发组件,并在 streamlit app中调用渲染。理论上,vue.js 等技术可以和 streamlit 结合使用了。

参考:Components API reference

© Licensed under CC BY-NC-SA 4.0

天地不仁,以万物为刍狗;圣人不仁,以百姓为刍狗。—— 老子

发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!