首页 > 编程问答 >仅从 Dash Python 中的表中提取过滤后的数据

仅从 Dash Python 中的表中提取过滤后的数据

时间:2024-08-03 05:40:26浏览次数:14  
标签:python plotly-dash

我用 Dash Python 构建了一个网站,并将 csv 文件的所有数据显示在一个可以过滤的表中。

我希望用户能够从表中提取数据。当没有过滤器时,我希望他能够提取完整的数据,当他过滤数据时,我希望他能够提取过滤后的数据。

为此,我使用 dcc.download 组件,它是工作得很好,我还使用 df (from df = pd.read_csv("./data.csv") ) 作为全局变量,以便能够在我的提取回调中重用它。

这是我的代码:

from dash import Dash, dash_table, dcc, html, State
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbc
import pandas as pd
import csv
import time
import xlsxwriter
from datetime import datetime
from dash_extensions.enrich import Output, DashProxy, Input, MultiplexerTransform
import os

app = DashProxy(external_stylesheets=[dbc.themes.BOOTSTRAP], transforms=[MultiplexerTransform()])
server = app.server

df = pd.read_csv("./data.csv")
df = df.fillna("NaN")
PAGE_SIZE = 20

# Layout
app.layout = html.Div(children=[
        dcc.Download(id="download-dataframe-csv"),
        dbc.Card([
            dbc.CardBody([
                dash_table.DataTable(
                    id='table-sorting-filtering',
                    columns=[{'name': i, 'id': i} for i in df.columns],
                    page_current= 0,
                    page_size= PAGE_SIZE,
                    page_action='custom',
                    filter_action='custom',
                    filter_query='',
                    sort_action='custom',
                    sort_mode='multi',
                    sort_by=[],
                    style_data={'text-align':'center'},
                    style_header={
                            'backgroundColor': 'white',
                            'fontWeight': 'bold',
                            'text-align':'center'
                        },
                    style_cell={'padding': '5px'},
                    style_as_list_view=True,
                )]
            )],
            style={"margin-left":"15px", "margin-right":"15px"}
        ),
        dcc.Interval(
                id='interval-component',
                interval=1*1000, # in milliseconds
                n_intervals=0
            ),
        ]
    )]
)


operators = [['ge ', '>='],
             ['le ', '<='],
             ['lt ', '<'],
             ['gt ', '>'],
             ['ne ', '!='],
             ['eq ', '='],
             ['contains ']]

def split_filter_part(filter_part):
    for operator_type in operators:
        for operator in operator_type:
            if operator in filter_part:
                name_part, value_part = filter_part.split(operator, 1)
                name = name_part[name_part.find('{') + 1: name_part.rfind('}')]
                value_part = value_part.strip()
                v0 = value_part[0]
                if (v0 == value_part[-1] and v0 in ("'", '"', '`')):
                    value = value_part[1: -1].replace('\\' + v0, v0)
                else:
                    try:
                        value = float(value_part)
                    except ValueError:
                        value = value_part
                return name, operator_type[0].strip(), value
    return [None] * 3

# Display data in table and manage filtering
@app.callback(
    Output('table-sorting-filtering', 'data'),
    Input('table-sorting-filtering', "page_current"),
    Input('table-sorting-filtering', "page_size"),
    Input('table-sorting-filtering', 'sort_by'),
    Input('table-sorting-filtering', 'filter_query'),
    Input('interval-component', 'n_intervals'))

def update_table(page_current, page_size, sort_by, filter, n):
    global df
    global date_time
    df = pd.read_csv("./data.csv")
    df = df.fillna("NaN")
    date_time = last_modification_time_of_csv("./data.csv")
    filtering_expressions = filter.split(' && ')
    for filter_part in filtering_expressions:
        col_name, operator, filter_value = split_filter_part(filter_part)
        if operator in ('eq', 'ne', 'lt', 'le', 'gt', 'ge'):
            # these operators match pandas series operator method names
            df = df.loc[getattr(df[col_name], operator)(filter_value)]
        elif operator == 'contains':
            if type(filter_value) is str:
                df = df.loc[df[col_name].str.contains(filter_value)]
    if len(sort_by):
        df = df.sort_values(
            [col['column_id'] for col in sort_by],
            ascending=[
                col['direction'] == 'asc'
                for col in sort_by
            ],
            inplace=False
        )
    page = page_current
    size = page_size
    return df.iloc[page * size: (page + 1) * size].to_dict('records')

# Export button
@app.callback(
    Output("download-dataframe-csv", "data"),
    Input("button_export", "n_clicks"),
    prevent_initial_call=True,
)
def export_on_click(n_clicks):
    global df
    return dcc.send_data_frame(df.to_excel, "export.xlsx")

if __name__ == '__main__':
    app.run_server(debug=True, host='0.0.0.0')

我注意到我有一些问题提取数据时。有时它工作得很好,有时我提取了我根本没有过滤的数据。所以我想知道全局变量是否是一个好的解决方案,因为我有多个用户使用我的网站。

我看到有一种方法可以在 Dash Python 中使用状态来做到这一点,但我不太明白它是如何工作的,如果这是我可以在我的情况下使用的东西。

有人可以帮助我吗?

谢谢


是对的,在 Dash 中使用全局变量来存储数据供多个用户使用不是一个好的解决方案。这会导致用户之间出现数据不一致和错误,因为所有用户都将共享相同的数据副本。

使用 dcc.Store 组件存储经过过滤的数据框,然后在的导出回调中访问它,这是一种更好的方法。

以下是更新后的代码:

from dash import Dash, dash_table, dcc, html, Input, Output, State
import dash_bootstrap_components as dbc
import pandas as pd
from dash_extensions.enrich import Output, DashProxy, Input, MultiplexerTransform

app = DashProxy(external_stylesheets=[dbc.themes.BOOTSTRAP], transforms=[MultiplexerTransform()])
server = app.server

df = pd.read_csv("./data.csv")
df = df.fillna("NaN")
PAGE_SIZE = 20

app.layout = html.Div(
    children=[
        dcc.Download(id="download-dataframe-csv"),
        dbc.Card(
            [
                dbc.CardBody(
                    [
                        dash_table.DataTable(
                            id='table-sorting-filtering',
                            columns=[{'name': i, 'id': i} for i in df.columns],
                            page_current=0,
                            page_size=PAGE_SIZE,
                            page_action='custom',
                            filter_action='custom',
                            filter_query='',
                            sort_action='custom',
                            sort_mode='multi',
                            sort_by=[],
                            style_data={'text-align': 'center'},
                            style_header={
                                'backgroundColor': 'white',
                                'fontWeight': 'bold',
                                'text-align': 'center'
                            },
                            style_cell={'padding': '5px'},
                            style_as_list_view=True,
                        )
                    ]
                )
            ],
            style={"margin-left": "15px", "margin-right": "15px"}
        ),
        dcc.Store(id='filtered-data'),  # 存储过滤后的数据
        html.Button("Download filtered data", id="button_export"),
        dcc.Interval(
            id='interval-component',
            interval=1 * 1000,  # in milliseconds
            n_intervals=0
        ),
    ]
)


operators = [['ge ', '>='],
             ['le ', '<='],
             ['lt ', '<'],
             ['gt ', '>'],
             ['ne ', '!='],
             ['eq ', '='],
             ['contains ']]


def split_filter_part(filter_part):
    for operator_type in operators:
        for operator in operator_type:
            if operator in filter_part:
                name_part, value_part = filter_part.split(operator, 1)
                name = name_part[name_part.find('{') + 1: name_part.rfind('}')]
                value_part = value_part.strip()
                v0 = value_part[0]
                if (v0 == value_part[-1] and v0 in ("'", '"', '`')):
                    value = value_part[1: -1].replace('\\' + v0, v0)
                else:
                    try:
                        value = float(value_part)
                    except ValueError:
                        value = value_part
                return name, operator_type[0].strip(), value
    return [None] * 3

# Display data in table and manage filtering
@app.callback(
    Output('table-sorting-filtering', 'data'),
    Output('filtered-data', 'data'),  # 将过滤后的数据存储在 dcc.Store 中
    Input('table-sorting-filtering', "page_current"),
    Input('table-sorting-filtering', "page_size"),
    Input('table-sorting-filtering', 'sort_by'),
    Input('table-sorting-filtering', 'filter_query'),
    Input('interval-component', 'n_intervals'))
def update_table(page_current, page_size, sort_by, filter, n):
    df = pd.read_csv("./data.csv")
    df = df.fillna("NaN")
    filtering_expressions = filter.split(' &amp;&amp; ')
    for filter_part in filtering_expressions:
        col_name, operator, filter_value = split_filter_part(filter_part)
        if operator in ('eq', 'ne', 'lt', 'le', 'gt', 'ge'):
            # these operators match pandas series operator method names
            df = df.loc[getattr(df[col_name], operator)(filter_value)]
        elif operator == 'contains':
            if type(filter_value) is str:
                df = df.loc[df[col_name].str.contains(filter_value)]
    if len(sort_by):
        df = df.sort_values(
            [col['column_id'] for col in sort_by],
            ascending=[
                col['direction'] == 'asc'
                for col in sort_by
            ],
            inplace=False
        )
    page = page_current
    size = page_size
    return df.iloc[page * size: (page + 1) * size].to_dict('records'), df.to_dict('records')


# Export button
@app.callback(
    Output("download-dataframe-csv", "data"),
    Input("button_export", "n_clicks"),
    State('filtered-data', 'data'),  # 从 dcc.Store 中获取过滤后的数据
    prevent_initial_call=True,
)
def export_on_click(n_clicks, filtered_data):
    df_filtered = pd.DataFrame.from_records(filtered_data)
    return dcc.send_data_frame(df_filtered.to_excel, "export.xlsx")


if __name__ == '__main__':
    app.run_server(debug=True, host='0.0.0.0')

在这个更新后的代码中:

  1. 我们添加了一个 dcc.Store 组件,用于存储过滤后的数据框。
  2. update_table 回调现在还返回过滤后的数据框,该数据框存储在 dcc.Store 组件中。
  3. export_on_click 回调现在从 dcc.Store 组件中获取过滤后的数据框,然后将其导出到 Excel 文件。

通过这些更改,不再需要使用全局变量,并且每个用户都将拥有自己的过滤数据副本以供导出。

标签:python,plotly-dash
From: 72591835

相关文章

  • 如何使用pipenv解决Python包依赖关系?
    我正在使用pipenv处理Python包依赖项。Python包使用两个包(名为pckg1和pckg2),它们依赖于名为pckg3的同一个包,但来自两个不同的包版本显示依赖关系树:$pipenvgraphpckg1==3.0.0-pckg3[required:>=4.1.0]......
  • 存在的开放路径不起作用 - python
    代码获取测试logs\log.jsonl的根路径,该路径在图像中显然在那里,但无法打开它#doesntworkdir_path=os.path.dirname(os.path.realpath(__file__))withopen(os.path.join(dir_path,"logs\\log.jsnol"),'r')asjsondata:data=json.load(jsondata)wit......
  • 如何在系统PATH中永久添加路径? - Python
    我正在为我的一个项目创建一个安装程序,下载该项目的二进制文件(在ZIP文件中),然后将其解压缩到操作系统程序文件夹中的一个目录中,我想将此目录添加到|||。我的脚本是一个带有UI的安装程序,其目的是编译为PATH/可执行文件。如果你能找到我一种.exe平台无关......
  • python数据分析与可视化基础
    一、数据分析介绍:1.数据分析含义:数据分析是指用适当的统计分析方法对收集来的大量数据进行分析,将它们加以汇总和理解并消化,以求最大化地开发数据的功能,发挥数据的作用。数据分析是为了提取有用信息和形成结论而对数据加以详细研究和概括总结的过程。数据分析的数学基础在20世纪早......
  • 为什么要设置 os.environ[“PYTHONHASHSEED“] = “0“,这样做具体会影响哪些随机值?
    ......
  • Python,Geopandas报错,AttributeError: The geopandas.dataset has been deprecated and
    Python版本3.9,Geopandas版本1.0.1问题描述:这是执行的代码,importpandasaspdimportgeopandasimportmatplotlib.pyplotaspltworld=geopandas.read_file(geopandas.datasets.get_path('naturalearth_lowres'))world.plot()plt.show()这是报错信息,Traceback(mo......
  • Python,Maskrcnn训练,cannot import name ‘saving‘ from ‘keras.engine‘ ,等问题集合
    Python版本=3.9,tensorflow=2.11.0,keras==2.11.0问题一、module'keras.engine'hasnoattribute'Layer'Traceback(mostrecentcalllast):File"C:\Users\Administrator\Desktop\20240801\代码\test.py",line16,in<module>......
  • 7-Python数据类型——列表和元组的详解(增删改查、索引、切片、步长、循环)
    一、列表1.1列表list有序且可变的容器,可以存放多个不同类型的元素列表就是专门用来记录多个同种属性的值列表:存储同一个类别的数据,方便操作字符串,不可变:即:创建好之后内部就无法修改【内置功能都是新创建一份数据】name="xiaochaun"data=name.upper()print(nam......
  • python中的 is 和 ==
    一前言环境:win10python3.10二is和isnot1比较对象的identityis和isnot是python的比较运算符,比较运算符除了这两个,还有下图中的这些is和isnot比较的是两个对象的是identityidentity是啥,内置函数id()返回的就是这个东西通过上面id函数的解释,现在知道,identi......
  • Python应用开发——30天学习Streamlit Python包进行APP的构建(23):构建多页面应用程序
    创建动态导航菜单通过st.navigation,可以轻松创建动态导航菜单。您可以在每次重新运行时更改传递给st.navigation的页面集,从而更改与之匹配的导航菜单。这是创建自定义、基于角色的导航菜单的便捷功能。本教程使用st.navigation和st.Page,它们是在Streamlit1.36.0版中......