搜尋

首頁  >  問答  >  主體

在 dash 應用程式中,如何交換不同容器的內容?

我在做以下事情時遇到了很大的困難。我有一個由 css 格式化的破折號應用程序,以顯示在不同的容器中。標記為“hexgrid-1-container”的容器是最大的容器,而其他容器較小,並圍繞該容器組織。我想更新我的破折號應用程序,以便每當單擊另一個容器中的圖形/圖形時,它都會出現在“hexgrid-1-container”中,而之前位於“hexgrid-1-container”中的圖形會出現在較小的容器中容器。

我有一個破折號應用程序,如下所示:

導入破折號
將 dash_core_components 導入為 dcc
將 dash_html_components 導入為 html
從 dash.dependencies 導入輸入、輸出、狀態
從 jupyter_dash 導入 JupyterDash
將plotly.express導入為px
導入plotly.graph_objects作為go
將 pandas 導入為 pd
導入sqlite3
導入語言環境
將 numpy 導入為 np
將plotly.figure_factory匯入為ff
將plotly.express導入為px

# 設定格式化的區域設置
locale.setlocale(locale.LC_ALL, '')
應用程式 = dash.Dash(__name__)
app.layout = html.Div(className='容器玻璃',children=[
    html.Div(className='hexgrid-1-container', style={'border': '1px 純黑'}, Children=[
        dcc.Graph(id='hexgrid-1', style={"height": "75%", "width": "100%"}, className='hexgrid1')
    ]),

    html.Div(className='hexgrid-2-container', style={'border': '1px 純黑'}, Children=[
        dcc.Graph(id='hexgrid-2', style={"height": "100%", "width": "100%"}, className='hexgrid2')
    ]),

    html.Div(className='base-plot-container', style={'border': '1px 純黑'}, Children=[
        dcc.Graph(id='base-plot', style={"height": "100%", "width": "100%"})
    ]),

    html.Div(className='us-map-container', style={'border': '1px 純黑'}, Children=[
        dcc.Graph(id='us-map-graph', style={"height": "100%", "width": "100%"})
    ]),

    html.Div(className='第五容器', style={'border': '1px 純黑'}, Children=[
        # dcc.Graph(id='us-map-graph', style={"height": "100%", "width": "100%"})
        #html.H2("第五個容器")
    ]),

    html.Div(className='第六個容器', style={'border': '1px 純黑'}, Children=[
        # dcc.Graph(id='us-map-graph', style={"height": "100%", "width": "100%"})
        #html.H2("第6個容器")
    ])
])


@app.callback(
    輸出('hexgrid-1','數字'),
    輸入('hexgrid-1','id')
)

def render_hexgrid_1(_):
    # 開啟一個新的資料庫連接
    conn = sqlite3.connect(r"C:\Users\HituJani\Downloads\txns.db")
    
    # 取得交易表中的所有欄位
    查詢='''
        PRAGMA table_info(交易)
    '''
    
    # 取得數據
    資料 = pd.read_sql_query(查詢, conn)
    
    # 過濾掉相關列,如果想要所有列可以跳過這一步驟。
    related_columns = data[data['name'].isin(['TranType', 'MessageTypeIdentifier', 'MerchantType', 'IResponseCode'])]
    
    # 使用列名建立十六進位網格
    plot_data = go.Scatter(x=relevant_columns.index, y=relevant_columns['name'], text=relevant_columns['name'],
                           標記=dict(符號='六邊形',大小=30),模式='標記文字')
    版面 = go.Layout(title="選擇類別")
    返回 go.Figure(data=[plot_data],layout=layout)
@app.callback(
    輸出('hexgrid-2','圖'),
    輸出('hexgrid-2','樣式'),
    輸入('hexgrid-1','clickData')
)
def render_hexgrid_2(clickData):
    # 開啟一個新的資料庫連接
    conn = sqlite3.connect(r"C:\Users\HituJani\Downloads\txns.db")
    
    如果 clickData 為 None:
        返回 go.Figure(), {"display": "none"}別的:
        類別 = clickData['點'][0]['文字']
        
        # 取得交易表中的所有欄位
        查詢='''
            PRAGMA table_info(交易)
        '''
        
        # 取得數據
        資料 = pd.read_sql_query(查詢, conn)
        
        # 過濾掉相關數值特徵列
        related_columns = data[data['name'].isin(['TransactionAmount', 'OutstandingAmount', 'CurrentBalance', 'TotalOutStgAuthAmt'])]
        
        # 在球體表面產生隨機點
        phi = np.random.uniform(0, np.pi, len(relevant_columns))
        theta = np.random.uniform(0, 2*np.pi, len(relevant_columns))
        
        x = np.cos(theta) * np.sin(phi)
        y = np.sin(theta) * np.sin(phi)
        z = np.cos(phi)
        
        # 使用球體標記建立 3D 散佈圖
        分散 = go.Scatter3d(
            x=x,
            y=y,
            z=z,
            mode='標記文字',
            標記=字典(
                大小=12,
                顏色=np.arange(len(relevant_columns)),
                colorscale='Viridis',
                符號='圓圈',
                不透明度=0.8
            ),
            文本=relevant_columns['名稱'],
            懸停訊息='文字'
        )
        
        # 使用網格建立線框球體
        u = np.linspace(0, 2 * np.pi, 100)
        v = np.linspace(0, np.pi, 100)
        x_sphere = np.outer(np.cos(u), np.sin(v))
        y_sphere = np.outer(np.sin(u), np.sin(v))
        z_sphere = np.outer(np.ones(np.size(u)), np.cos(v))
        
        球體 = go.Mesh3d(x=x_sphere.ravel(),
                           y=y_sphere.ravel(),
                           z=z_sphere.ravel(),
                           不透明度=0.1,
                           顏色='青色')
        
        # 將散佈圖和線框圖合併為一個圖形
        Fig = go.Figure(data=[散點圖, 球體])
        
        圖.update_layout(
            邊距=dict(l=0, r=0, b=0, t=0),
            場景=字典(
                xaxis=dict(標題=無,可見=假),
                yaxis=dict(標題=無,可見=假),
                zaxis=dict(標題=無,可見=假),
            ),
            模板='plotly_dark'
        )
        
        返回無花果,{“高度”:“50vh”,“寬度”:“100%”,“顯示”:“內聯塊”}
# 定義將更新繪圖、反白球體並啟用向下鑽取的回呼函數
@app.callback(
    輸出('基本圖','圖'),
    輸入('hexgrid-2','clickData'),
    狀態('hexgrid-1','clickData')
)
def update_base_plot(clickData_hexgrid_2, clickData_hexgrid_1):
    嘗試:
        # 開啟一個新的資料庫連接
        conn = sqlite3.connect(r"C:\Users\HituJani\Downloads\txns.db")

        類別 = clickData_hexgrid_1['點'][0]['文字']
        numeric_feature = clickData_hexgrid_2['點'][0]['文字']

        # SQL 查詢根據選定的類別和數值特徵檢索聚合數據
        查詢 = f'''
            SELECT {category}, WeekOfMonth, SUM({numerical_feature}) AS 總計金額
            來自交易
            按{類別}分組, 每月一周
            以總金額 DESC 排序
        '''

        # 從資料庫取得數據
        df_base = pd.read_sql(查詢, conn)

        # 關閉資料庫連接
        conn.close()

        # 設定總計列的格式
        df_base['TotalAmount'] = df_base['TotalAmount'].apply(lambda x: locale.currency(x, grouping=True))

        # 使用球體標記建立 3D 散佈圖
        圖 = go.Figure()

        # 定義 WeekOfMonth 值的色階
        色階 = [
            [0, '藍色'], # 第 1 週:藍色
            [0.25, '紫色'], # 第 2 週:紫色
            [0.5, 'darkorange'], # 第 3 週:深橙色
            [0.75, '黃色'], # 第 4 週:黃色
            [1, '粉紅色'] # 第 5 週:粉紅色
        ]

        # 新增散點圖軌跡
        圖.add_trace(
            去.Scatter3d(
                x=df_base[類別],
                y=df_base['WeekOfMonth'].astype(int),
                z=df_base['總金額'],
                mode='標記文字',
                標記=字典(
                    size=5, # 調整標記的大小,使其變小
                    symbol='circle', # 使用 'circle' 符號表示球體
                    顏色=df_base['WeekOfMonth'],
                    色標=色標,
                ),
                textposition='頂部中心',
                懸停模板=(
                    f"<b>{類別}</b>: %{{x}}<br>"
                    “<b>總金額</b>:%{z}<br>”
                    “<b>每月週</b>:%{y}<br>”
                )
            )
        )

        # 動態設定y軸範圍
        y_max = df_base['WeekOfMonth'].max()

        圖.update_layout(
            場景=字典(
                x軸=字典(
                    標題=類別,
                    title_font = dict(大小= 14,顏色='暗橙色'),
                    visible=False # 隱藏x軸
                ),
                y軸=字典(
                    title='一個月中的第幾週',
                    title_font = dict(大小= 14,顏色='紫色'),
                    勾選模式='數組',
                    刻度值=[0.5, 1.5, 2.5, 3.5, 4.5, 5.5],
                    ticktext=['1', '2', '3', '4', '5'], # 將刻度標籤顯示為 1, 2, 3, 4, 5],
                    visible=False # 隱藏 y 軸
                ),
                z軸=字典(
                    title=f'總計{numerical_feature} ($)',
                    title_font = dict(大小= 14,顏色='黃色'),
                    自動範圍='反轉',
                    visible=False # 隱藏 z 軸
                ),
            ),
            x軸=字典(
                型態='類別',
                刻度模式='線性',
                刻度角=45,
                自動保證金=真,
                visible=False # 隱藏x軸標籤
            ),
            margin=dict(l=10, r=10, t=10, b=10), # 增加b值以放大檢視窗口
            模板='plotly_dark',
        )

        返回無花果

    除了異常 e:
        列印(f“錯誤:{e}”)
        返回 go.Figure()


@app.callback(
    輸出('美國地圖圖','圖'),
    輸出('我們地圖圖','風格'),
    輸入('基本圖','clickData'),
    狀態('hexgrid-1','clickData'),
    狀態('hexgrid-2','clickData')
)
def display_transaction_amount(base_plot_click_data, hexgrid_1_clickData, hexgrid_2_clickData):
    嘗試:
        # 檢查hexgrid-1和hexgrid-2的資料是否可用
        如果 hexgrid_1_clickData 為 None 或 hexgrid_2_clickData 為 None:
            # 傳回一個空圖形並隱藏地圖
            返回 go.Figure(), {"display": "none"}

        # 從hexgrid-1中取得選定的類別,從hexgrid-2中取得數值特徵
        selected_category = hexgrid_1_clickData['點'][0]['文字']
        numeric_feature = hexgrid_2_clickData['點'][0]['文字']

        # 從base_plot_click_data取得選定的子類別
        選定的子類別=無
        如果 base_plot_click_data 不是 None:
            selected_subcategory = base_plot_click_data['點'][0]['x']

        # 開啟一個新的資料庫連接
        conn = sqlite3.connect(r"C:\Users\HituJani\Downloads\txns.db")

        # SQL 查詢會依狀態擷取所選類別、子類別和數字特徵的交易數據
        查詢 = f'''
            SELECT StateCode, {selected_category}, SUM({numerical_feature}) AS TotalTransactionAmount
            來自交易
            哪裡 {selected_category} = ?
            按州代碼分組,{selected_category}
        '''

        # 執行查詢並將結果擷取到DataFrame中
        state_data = pd.read_sql(query, conn, params=(selected_subcategory,))

        # 關閉資料庫連接
        conn.close()

        # 使用過濾後的資料建立 Choropleth 地圖
        無花果 = px.choropleth(
            數據幀=狀態數據,
            locationmode='美國各州',
            位置='州代碼',
            範圍='美國',
            color='總交易金額',
            hide_data={'StateCode': True, 'TotalTransactionAmount': ':$,f'},
            color_continuous_scale='紅色',
            labels={'TotalTransactionAmount': '交易總金額'},
            模板='plotly_dark'
        )

        圖.update_traces(
            hidetemplate="<b>%{customdata[0]}</b><br>"
                          "<b>總交易金額</b>: $%{customdata[1]:,.2f}<br>",
            customdata=list(zip(state_data['StateCode'], state_data['TotalTransactionAmount']))
        )

        圖.update_layout(
            title_text=f'類別:{selected_category}、子類別:{selected_subcategory}的州總交易金額',
            title_xanchor='中心',
            title_font=dict(大小=12),
            標題_x=0.5,
            地理=字典(範圍='美國'),
        )

        # 返回圖形並設定顯示樣式為block(可見)
        返回無花果,{“顯示”:“塊”}

    除了異常 e:
        列印(f“錯誤:{e}”)
        返回 go.Figure(), {"display": "none"}
如果 __name__ == '__main__':
    app.run_server(debug=True, use_reloader=False)

另外,我還有這個整理網頁的css檔:

/* styles.css */

。容器 {
  顯示:網格;
  網格模板行:1fr 1fr 1fr;
  網格模板列:1fr 1fr 1fr;
  網格列間隙:15px;
  網格行間距:15px;
  背景圖像: url("https://plainbackground.com/plain1024/383c3d.png");
  背景大小:100%;
  背景位置:網格-ce;
}

.hexgrid-1-container {
  /* 網格區域: 1/1/3/3; */
  網格行:跨度2;
  網格列:跨度 2;
  內邊距:2 像素 2 像素 2 像素 2 像素;
  邊框:1px 實心 hsl(176, 87%, 7%, 0.6);
  邊框半徑:10px;
  框陰影: rgba(250, 118, 3, 0.4) -5px 5px, rgba(250, 118, 3, 0.3) -10px 10px, rgba(250, 118, 3, 0.2) -15px
  背景:hsla(0, 7%, 11%, 0.9);
  位置:相對;
}

.hexgrid-2-container {
  網格面積:1/3/2/4;
  填充:3rem 4rem 4rem;
  寬度:70%;
  邊框:1px 實心 hsl(176, 87%, 7%, 0.6);
  邊框半徑:10px;
  框陰影: rgba(250, 118, 3, 0.4) -5px 5px, rgba(250, 118, 3, 0.3) -10px 10px, rgba(250, 118, 3, 0.2) -15px
  背景:hsl(0, 7%, 11%, 0.9);
  位置:相對;
}

.base-plot-container {
  /* 在此新增基本圖容器的自訂樣式 */
  網格面積:2/3/3/4;
  填充:3rem 4rem 4rem;
  寬度:70%;
  邊框:1px 實心 hsl(176, 87%, 7%, 0.6);
  邊框半徑:10px;
  框陰影: rgba(250, 118, 3, 0.4) -5px 5px, rgba(250, 118, 3, 0.3) -10px 10px, rgba(250, 118, 3, 0.2) -15px
  背景:hsl(0, 7%, 11%, 0.9);
  位置:相對;
}

.us-map-container {
  網格面積:3/3/4/4;
  填充:3rem 4rem 4rem;
  寬度:70%;
  /* 位置:固定; */
  邊框:1px 實心 hsl(176, 87%, 7%, 0.6);
  邊框半徑:10px;
  框陰影: rgba(250, 118, 3, 0.4) -5px 5px, rgba(250, 118, 3, 0.3) -10px 10px, rgba(250, 118, 3, 0.2) -15px
  背景:hsl(0, 7%, 11%, 0.9);
  位置:相對;
}

.第五容器{
  網格面積:3/2/4/3;
  邊框:1px 實心 hsl(176, 87%, 7%, 0.6);
  邊框半徑:10px;
  框陰影: rgba(250, 118, 3, 0.4) -5px 5px, rgba(250, 118, 3, 0.3) -10px 10px, rgba(250, 118, 3, 0.2) -15px
  背景:hsl(0, 7%, 11%, 0.9);
  位置:相對;
}

.第六個容器{
  網格面積:3/1/4/2;
  邊框:1px 實心 hsl(176, 87%, 7%, 0.6);
  邊框半徑:10px;
  框陰影: rgba(250, 118, 3, 0.4) -5px 5px, rgba(250, 118, 3, 0.3) -10px 10px, rgba(250, 118, 3, 0.2) -15px
  背景:hsl(0, 7%, 11%, 0.9);
  位置:相對;
}

我嘗試更新回調函數,但進展不大,而且似乎我做錯了很多事情。實現此功能的最直接方法是什麼?先謝謝您。

P粉378890106P粉378890106276 天前577

全部回覆(1)我來回復

  • P粉252423906

    P粉2524239062024-02-27 15:34:56

    您可以進行回呼來偵聽點擊事件,交換圖形位置,然後將圖形回到更新的位置。您需要根據您的用例設定點擊邏輯。你可以實現這樣的東西:

    @app.callback(
        Output('hexgrid-1-container', 'children'),
        Output('hexgrid-2-container', 'children'),
        Input('hexgrid-2', 'clickData'),
        State('hexgrid-1-container', 'children'),
        State('hexgrid-2-container', 'children')
    )
    def swap_graphs(clickData, hexgrid_1_children, hexgrid_2_children):
        clicked_graph_id = 1 # Assuming hexgrid-2 was clicked, you can change this logic based on your use case
    
        if clicked_graph_id == 1:
            # Swap graph between hexgrid-1 and hexgrid-2
            return hexgrid_2_children, hexgrid_1_children
    
        return hexgrid_1_children, hexgrid_2_children
    #

    回覆
    0
  • 取消回覆