Py.Cafe

marie-anne/

figurefriday-2025-w37

Don't make me think :-)

DocsPricing
  • app.py
  • data.csv
  • requirements.txt
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# -*- coding: utf-8 -*-
"""
Created on Thu Feb 20 15:00:14 2025

@author: win11
"""

import dash
from dash import dcc, html, callback,clientside_callback, Input, Output, Patch
import pandas as pd
import dash_bootstrap_components as dbc
import plotly.graph_objects as go




#LAYOUT STUFF
#from dash_bootstrap_templates import load_figure_template
#import plotly.io as pio

#load_figure_template(["vizro", "vizro_dark"])
vizro_bootstrap = "https://cdn.jsdelivr.net/gh/mckinsey/vizro@main/vizro-core/src/vizro/static/css/vizro-bootstrap.min.css?v=2"



select_status = html.Div(
    [
        dbc.Label("Select view"),
        dbc.RadioItems(
            options=[
        {"label": "Completed", "value": "Completed"},
        {"label": "Pending", "value": "Pending"},
        {"label": "Cancelled", "value": "Cancelled"},

        {"label": "All orders", "value": "All"}
            ],
            value='Completed',
            id="select_order_status",
            inline = True,
        ),
    ], style={'backgroundColor': '#0d585e'}
)




# READ AND PROCESS DATA STATIONS
data_all = pd.read_csv('data.csv')


#convert date field to date type
data_all["Date"] = pd.to_datetime(data_all["Date"], format='%d-%m-%y', errors='coerce')
#add day of the week (0=Monday, 6=Sunday)
data_all["Weekday Num"] = data_all["Date"].dt.weekday
data_all["Day of Week"] = data_all["Date"].dt.strftime("%a")
#create a weekday map for mapping int to str.
weekday_map = {0:'mon', 1:'tue',2:'wed',3:'thu', 4:'fri', 5:'sat', 6:'sun'}


#replace Home Appliances with Home App., fits better on screen
data_all['Category'] = data_all['Category'].apply(lambda x: "Home App." if x == "Home Appliances" else x)



# Initialize the Dash app




app = dash.Dash(__name__, suppress_callback_exceptions=True, external_stylesheets=[vizro_bootstrap, dbc.icons.FONT_AWESOME])

# Define the app layout
app.layout = dbc.Container([
    dbc.Row([
        dbc.Col([select_status])
        
        ], style={'textAlign': 'center'}),


    dbc.Row([
        dbc.Col(dcc.Graph(id="heatmap_weekday3"), width=6),
        dbc.Col(dcc.Graph(id="heatmap_weekday4"), width=6)


        ],style={"marginBottom":"2rem"}),


], style={'padding': '3rem'})




#callback update visuals based on filters

@callback(

    Output('heatmap_weekday3', 'figure'),
    Output('heatmap_weekday4', 'figure'),    
    Input("select_order_status", "value")
)
def update_heatmaps(value):
    df = data_all.copy()
    if value == None or value == "All":
        dff = df
    else:
        dff = df[df['Status'] == value]
    

    
  
    
    # Similar logic for payment method heatmaps

    df_cat_payment = dff.groupby(['Category','Payment Method']).agg({
        'Order ID': 'count',
        'Total Sales': 'sum'
    }).reset_index()
    
    if value != "All" and value is not None:
        df_cat_payment_total = df.groupby(['Category','Payment Method']).agg({
            'Order ID': 'count',
            'Total Sales': 'sum'
        }).reset_index()
        
        df_cat_payment = df_cat_payment.merge(
            df_cat_payment_total, 
            on=['Category', 'Payment Method'], 
            how='right',
            suffixes=('_filtered', '_total')
        ).fillna(0)
        
        df_cat_payment['Order_Percentage'] = (df_cat_payment['Order ID_filtered'] / df_cat_payment['Order ID_total'] * 100).round(1)
        df_cat_payment['Sales_Percentage'] = (df_cat_payment['Total Sales_filtered'] / df_cat_payment['Total Sales_total'] * 100).round(1)
        
        # Use actual values for coloring, percentages for text
        z_values_orders_payment = df_cat_payment['Order ID_filtered']  # Actual values for color
        z_values_sales_payment = df_cat_payment['Total Sales_filtered']  # Actual values for color
        z_values_percentage_payment = df_cat_payment['Sales_Percentage']  # Percentages for color
        text_orders_payment = [f"{row['Order ID_filtered']}<br>({row['Order_Percentage']}%)" for _, row in df_cat_payment.iterrows()]
        text_sales_payment = [f"${row['Total Sales_filtered']}<br>({row['Sales_Percentage']}%)" for _, row in df_cat_payment.iterrows()]
        text_percentage_payment = [f"{row['Sales_Percentage']}%" for _, row in df_cat_payment.iterrows()]
        
    else:
        z_values_orders_payment = df_cat_payment['Order ID']
        z_values_sales_payment = df_cat_payment['Total Sales']
        z_values_percentage_payment = [100] * len(df_cat_payment)  # All 100% when showing all data
        text_orders_payment = df_cat_payment['Order ID'].astype(str)
        text_sales_payment = df_cat_payment['Total Sales'].astype(str)
        text_percentage_payment = ["100%"] * len(df_cat_payment)

    # Payment method heatmaps
    fig_heatmap_weekday3 = go.Figure(data=go.Heatmap(
        x=df_cat_payment['Payment Method'],
        y=df_cat_payment['Category'],
        z=z_values_orders_payment,  # Colors based on actual values
        colorscale="Mint_r",
        text=text_orders_payment,   # Text shows values + percentages
        texttemplate="%{text}",
        hovertemplate="Category: %{y}<br>Payment Method: %{x}<br>Value: %{text}<extra></extra>"
    ))
    title_suffix = "" if value == "All" else f" (% of total)"
    fig_heatmap_weekday3.update_layout(
        title=f'{value} orders (#){title_suffix} by payment method, category',
        template="plotly_dark",
    )

    fig_heatmap_weekday4 = go.Figure(data=go.Heatmap(
        x=df_cat_payment['Payment Method'],
        y=df_cat_payment['Category'],
        z=z_values_sales_payment,  # Colors based on actual values
        colorscale="Mint_r",
        text=text_sales_payment,   # Text shows values + percentages
        texttemplate="%{text}",
        hovertemplate="Category: %{y}<br>Payment Method: %{x}<br>Value: %{text}<extra></extra>"
    ))
    
    fig_heatmap_weekday4.update_layout(
        title=f'{value} ordervalue ($){title_suffix} by payment method, category',
        template="plotly_dark",
    )
    

    
    return fig_heatmap_weekday3, fig_heatmap_weekday4
    







# Run the app
if __name__ == '__main__':
    app.run(debug=True)