dcc.Store#

参考:dcc.Store | Dash for Python Documentation | Plotly

dcc.Store 组件用于在浏览器中存储 JSON 数据。

点击的例子#

from dash import dcc, html
from dash.dependencies import Input, Output, State
from dash.exceptions import PreventUpdate
from app import app
import dash
dash.register_page(__name__)

layout = html.Div([
    # 每次刷新页面时,内存存储都会恢复到默认值
    dcc.Store(id='memory'),
    # 本地存储只会在页面第一次加载时获取初始数据,
    # 并一直保存到页面被清除为止。
    dcc.Store(id='local', storage_type='local'),
    # 与本地存储相同,但当浏览器/选项卡关闭时将丢失数据。
    dcc.Store(id='session', storage_type='session'),
    html.Table([
        html.Thead([
            html.Tr(html.Th('点击存储在:', colSpan="3")),
            html.Tr([
                html.Th(html.Button('memory', id='memory-button')),
                html.Th(html.Button('localStorage', id='local-button')),
                html.Th(html.Button('sessionStorage', id='session-button'))
            ]),
            html.Tr([
                html.Th('内存点击'),
                html.Th('本地点击'),
                html.Th('会话点击')
            ])
        ]),
        html.Tbody([
            html.Tr([
                html.Td(0, id='memory-clicks'),
                html.Td(0, id='local-clicks'),
                html.Td(0, id='session-clicks')
            ])
        ])
    ])
])

# 为每个存储创建两个回调
for store in ('memory', 'local', 'session'):
    # 向适当的存储添加一个单击
    @app.callback(Output(store, 'data'),
                  Input(f'{store}-button', 'n_clicks'),
                  State(store, 'data'))
    def on_click(n_clicks, data):
        if n_clicks is None:
            # 阻止 None 回调对存储组件很重要。
            # 您不会想什么也不更新存储。
            raise PreventUpdate
        # 如果没有数据,给出一个默认的数据字典,点击 0 次。
        data = data or {'clicks': 0}
        data['clicks'] = data['clicks'] + 1
        return data

    # 在表格单元格中输出存储的单击。
    @app.callback(Output(f'{store}-clicks', 'children'),
                  # 因为我们在输出中使用了 data 属性,
                  # 所以我们无法通过 data 属性获得加载时的初始数据。为了应对这种情况,
                  # 可以使用 modified_timestamp 作为 Input,使用 data 作为 State。
                  # 这个限制是由于初始的 None 回调
                  # https://github.com/plotly/dash-renderer/pull/81
                  Input(store, 'modified_timestamp'),
                  State(store, 'data'))
    def on_data(ts, data):
        if ts is None:
            raise PreventUpdate
        data = data or {}
        print('data', data)
        return data.get('clicks', 0)

在回调之间共享数据#

import collections
import pandas as pd

from dash.dependencies import Output, Input
from dash.exceptions import PreventUpdate
from dash import dcc, html
from dash import dash_table
from sanstyle.github.file import lfs_url

from app import app
import dash
dash.register_page(__name__)
url = lfs_url('SanstyleLab/plotly-dastsets',
              'gapminderDataFiveYear.csv')
df = pd.read_csv(url)
countries = set(df['country'])


layout = html.Div([
    dcc.Store(id='memory-output'),
    dcc.Dropdown(id='memory-countries', options=[
        {'value': x, 'label': x} for x in countries
    ], multi=True, value=['Canada', 'United States']),
    dcc.Dropdown(id='memory-field', options=[
        {'value': 'lifeExp', 'label': 'Life expectancy'},
        {'value': 'gdpPercap', 'label': 'GDP per capita'},
    ], value='lifeExp'),
    html.Div([
        dcc.Graph(id='memory-graph'),
        dash_table.DataTable(
            id='memory-table',
            columns=[{'name': i, 'id': i} for i in df.columns]
        ),
    ])
])


@app.callback(Output('memory-output', 'data'),
              Input('memory-countries', 'value'))
def filter_countries(countries_selected):
    if not countries_selected:
        # 返回初始加载/没有选定国家时的所有行。
        return df.to_dict('records')
    filtered = df.query('country in @countries_selected')
    return filtered.to_dict('records')


@app.callback(Output('memory-table', 'data'),
              Input('memory-output', 'data'))
def on_data_set_table(data):
    if data is None:
        raise PreventUpdate
    return data


@app.callback(Output('memory-graph', 'figure'),
              Input('memory-output', 'data'),
              Input('memory-field', 'value'))
def on_data_set_graph(data, field):
    if data is None:
        raise PreventUpdate
    aggregation = collections.defaultdict(
        lambda: collections.defaultdict(list)
    )
    for row in data:
        a = aggregation[row['country']]
        a['name'] = row['country']
        a['mode'] = 'lines+markers'
        a['x'].append(row[field])
        a['y'].append(row['year'])
    return {'data': list(aggregation.values())}

Storage 的限制#

  • 浏览器的最大存储空间由以下因素决定:

    • 手机或笔记本电脑。

    • 在浏览器中,一个复杂的算法在配额管理(Quota Management)中实现。

    • UTF-16 的存储编码最终只能节省 UTF-8 的一半大小。

    • 一般来说,在大多数环境中存储 2MB 是安全的,而在大多数只有桌面的应用程序中存储 5~10MB 是安全的。

  • modified_timestamp 为只读。

检索初始存储数据#

如果使用 data 属性作为输出,则无法使用 data 属性获得加载时的初始数据。为了应对这种情况,可以使用 modified_timestamp 作为 Input,使用 data 作为 State

dcc.Store 属性#

id(字符串;必需):此组件的 ID,用于在回调中识别 Dash 组件。ID 需要在应用程序的所有组件中是唯一的。

  • clear_data(布尔;默认 False):设置为 True 删除 data_key 中包含的数据。

  • data(dict | list | number | string | boolean;可选):id 的存储数据。

  • modified_timestamp(数字;默认 -1):上次修改存储的时间。

  • storage_type('local', 'session', 'memory'(默认)):网络存储的类型。memory:只保留在内存中,刷新页面时重置。 localwindow.localStorage,浏览器退出后保留数据。session:window.sessionStorage,一旦浏览器退出,数据将被清除。