本文示例代碼已上傳至個人
Github
倉庫https://github.com/CNFeffery/DataScienceStudyNoteshtml
這是個人系列教程Python+Dash快速web應用開發的第十三期,在上一期中,咱們一塊兒認識了Dash
自帶的交互式表格組件dash_table
,並學會了如何自定義表格中不一樣部分的樣式。前端
而今天的教程,咱們將繼續深刻認識dash_table
的更多交互方面的功能,學習如何爲渲染出的表格分頁,並添加動態內容修改等交互功能。mysql
dash_table
的核心功能是賦予用戶與圖表進行快捷交互的能力,下面咱們來學習其基礎經常使用的一些交互功能:git
當咱們要展現的數據行數較多時,在網頁中渲染能夠選擇分頁,這在dash_table
中實現起來比較方便,根據數據傳遞方式的不一樣,能夠分爲前端分頁與後端分頁:github
前端分頁顧名思義,就是在咱們訪問Dash
應用時,表格內全部頁面的數據一次性加載完成,適合數據量不大的狀況,將數據存儲壓力置轉移到瀏覽器端。web
經過參數page_size
設置每頁要顯示的記錄行數,Dash
會自動幫咱們分好頁,並配上翻頁部件:sql
app1.py數據庫
import dash import dash_bootstrap_components as dbc import dash_table import seaborn as sns df = sns.load_dataset('tips') df.insert(0, '#', df.index) app = dash.Dash(__name__) app.layout = dbc.Container( [ dash_table.DataTable( id='dash-table', data=df.to_dict('records'), columns=[ {'name': column, 'id': column} for column in df.columns ], page_size=15, # 設置單頁顯示15行記錄行數 style_header={ 'font-family': 'Times New Romer', 'font-weight': 'bold', 'text-align': 'center' }, style_data={ 'font-family': 'Times New Romer', 'text-align': 'center' } ) ], style={ 'margin-top': '50px' } ) if __name__ == '__main__': app.run_server(debug=True)
### 2.1.2 後端分頁bootstrap
雖然前端分頁簡單易用,但當咱們的數據很大時,強行使用前端分頁會給網絡傳輸和瀏覽器端帶來不小的延遲和內存壓力,嚴重影響用戶體驗,所以Dash
貼心地爲咱們準備了後端分頁方式。後端
這時首先咱們得爲DataTable
設置參數page_action='custom'
,這是使用後端分頁的先決條件,接下來咱們須要認識一些新的參數:
page_current
,int型,對應當前翻到的頁碼;
page_count
,int型,對應顯示的總頁數;
咱們在使用後端分頁時,實際上就是經過用戶當前翻到的頁碼,以及設定的page_size
,來動態地在翻頁後加載對應批次的數據,並控制顯示的總頁數,參考下面這個簡單的例子:
app2.py
import dash import dash_bootstrap_components as dbc import dash_table from dash.dependencies import Input, Output import seaborn as sns import pandas as pd from tqdm import tqdm # 壓力測試 df = pd.concat([sns.load_dataset('tips') for _ in tqdm(range(1000))], ignore_index=True) df.insert(0, '#', df.index) app = dash.Dash(__name__) app.layout = dbc.Container( [ dbc.Spinner( dash_table.DataTable( id='dash-table', columns=[ {'name': column, 'id': column} for column in df.columns ], page_size=15, # 設置單頁顯示15行記錄行數 page_action='custom', page_current=0, style_header={ 'font-family': 'Times New Romer', 'font-weight': 'bold', 'text-align': 'center' }, style_data={ 'font-family': 'Times New Romer', 'text-align': 'center' } ) ) ], style={ 'margin-top': '50px' } ) @app.callback( [Output('dash-table', 'data'), Output('dash-table', 'page_count')], [Input('dash-table', 'page_current'), Input('dash-table', 'page_size')] ) def refresh_page_data(page_current, page_size): return df.iloc[page_current * page_size:(page_current + 1) * page_size].to_dict('records'), 1 + df.shape[ 0] // page_size if __name__ == '__main__': app.run_server(debug=True)
能夠看到,即便咱們完整的數據集被我concat
到24萬行,加載應用以及網頁內翻頁時依然輕鬆自如毫無壓力,在實際應用中你還能夠將翻頁部分改爲受到LIMIT
與OFFSET
控制的數據庫查詢過程,使得應用運行的更加快速高效:
講完了分頁翻頁,接下來咱們來學習dash_table
中更增強大的功能——單元格內容編輯。
一個現代化的web應用固然不能侷限於僅僅查看數據這麼簡單,Dash
一樣賦予了咱們雙擊數據表單元格進行數據編輯的能力,首先得設置參數editable=True
,即開啓表格編輯模式,接下來就能夠對數據區域單元格進行任意的雙擊選中編輯。
不過Dash
默認的單元格被選中的樣式忒醜了(是粉色的你敢信),所以咱們能夠利用下面的參數設置方式來自定義美化:
style_data_conditional=[ { # 對選中狀態下的單元格進行自定義樣式 "if": {"state": "selected"}, "background-color": "#b3e5fc", "border": "none" }, ]
來看一個形象的例子,咱們對前端分頁方式渲染出的表格進行隨意的修改,並在下方對利用pandas
的compare
比較出的數據框之間的差別結果進行打印:
app3.py
import dash import dash_html_components as html import dash_core_components as dcc import dash_bootstrap_components as dbc import dash_table from dash.dependencies import Input, Output import seaborn as sns import pandas as pd df = sns.load_dataset('tips') df.insert(0, '#', df.index) app = dash.Dash(__name__) app.layout = dbc.Container( [ dash_table.DataTable( id='dash-table', data=df.to_dict('records'), columns=[ {'name': column, 'id': column} for column in df.columns ], fixed_rows={'headers': True}, page_size=15, editable=True, style_header={ 'font-family': 'Times New Romer', 'font-weight': 'bold', 'text-align': 'center' }, style_data={ 'font-family': 'Times New Romer', 'text-align': 'center' }, style_data_conditional=[ { # 對選中狀態下的單元格進行自定義樣式 "if": {"state": "selected"}, "background-color": "#b3e5fc", "border": "none" }, ] ), html.H4('與原表格內容比較:', style={'margin-top': '50px'}), dcc.Markdown( '無差異', id='markdown', dangerously_allow_html=True ) ], style={ 'margin-top': '50px' } ) @app.callback( Output('markdown', 'children'), Input('dash-table', 'data'), prevent_initial_call=True ) def compare_difference(dash_table_data): print(pd.DataFrame(dash_table_data)) return df.compare(pd.DataFrame(dash_table_data)).to_html() if __name__ == '__main__': app.run_server(debug=True)
能夠看到,咱們成功地對指定單元格元素進行了修改。
在學習完今天的內容以後,咱們就能夠開發一個簡單的,可在線自由修改並同步變更到數據庫的小工具,這裏咱們以MySQL
數據庫爲例,對示例表進行修改和更新:
首先咱們利用下列代碼向示例數據庫中新建表格tips
:
from sqlalchemy import create_engine import seaborn as sns df = sns.load_dataset('tips') df.insert(0, '#', df.index) engine = create_engine('mysql+pymysql://root:mysql@localhost/DASH') df.to_sql('tips', con=engine, if_exists='replace', index=False)
接下來咱們就以建立好的tips
表爲例,開發一個Dash
應用,進行數據的修改和更新到數據庫:
效果很是的不錯,你能夠在我這個簡單示例的基礎上,拓展更多新功能,也能夠採起後端分頁+條件修改的方式來應對大型數據表的修改,所有代碼以下:
app4.py
import dash import dash_bootstrap_components as dbc import dash_core_components as dcc import dash_html_components as html import dash_table from dash.dependencies import Input, Output, State from sqlalchemy import create_engine import pandas as pd engine = create_engine('mysql+pymysql://root:mysql@localhost/DASH') app = dash.Dash(__name__) app.layout = dbc.Container( [ dbc.Row( [ dbc.Col(dbc.Button('更新數據表', id='refresh-tables', style={'width': '100%'}), width=2), dbc.Col(dcc.Dropdown(id='table-select', style={'width': '100%'}), width=2) ] ), html.Hr(), dash_table.DataTable( id='dash-table', editable=True, page_size=15, style_header={ 'font-family': 'Times New Romer', 'font-weight': 'bold', 'text-align': 'center' }, style_data={ 'font-family': 'Times New Romer', 'text-align': 'center' }, style_data_conditional=[ { # 對選中狀態下的單元格進行自定義樣式 "if": {"state": "selected"}, "background-color": "#b3e5fc", "border": "none" }, ] ), dbc.Button('同步變更到數據庫', id='update-tables', style={'display': 'none'}), html.P(id='message') ], style={ 'margin-top': '50px' } ) @app.callback( Output('table-select', 'options'), Input('refresh-tables', 'n_clicks') ) def refresh_tables(n_clicks): if n_clicks: return [ { 'label': table, 'value': table } for table in pd.read_sql_query('SHOW TABLES', con=engine)['Tables_in_dash'] ] return dash.no_update @app.callback( [Output('dash-table', 'data'), Output('dash-table', 'columns'), Output('update-tables', 'style')], Input('table-select', 'value') ) def render_dash_table(value): if value: df = pd.read_sql_table(value, con=engine) return df.to_dict('records'), [ {'name': column, 'id': column} for column in df.columns ], {'margin-top': '25px'} else: return [], [], {'display': 'none'} @app.callback( [Output('message', 'children'), Output('message', 'style')], Input('update-tables', 'n_clicks'), [State('dash-table', 'data'), State('table-select', 'value')] ) def update_to_database(n_clicks, data, value): if n_clicks: try: pd.DataFrame(data).to_sql(value, con=engine, if_exists='replace', index=False) return '更新成功!', {'color': 'green'} except Exception as e: return f'更新失敗!{e}', {'color': 'red'} return dash.no_update if __name__ == '__main__': app.run_server(debug=True)
以上就是本文的所有內容,歡迎在評論區發表你的意見與觀點。