|
| 1 | +import logging |
1 | 2 | import plotly.express as px |
2 | 3 | from dash import dash_table, dcc, html |
3 | 4 | from dash.dependencies import Input, Output |
4 | 5 | from django_plotly_dash import DjangoDash |
| 6 | +import dash_bootstrap_components as dbc |
| 7 | +from datetime import datetime |
5 | 8 |
|
6 | | -from .functions import fetch_data, prepare_livelihood_data, prepare_wealth_group_data |
7 | | - |
8 | | -# API Endpoints |
9 | | -LIVELIHOOD_STRATEGY_URL = "https://headev.fews.net/api/livelihoodstrategy/" |
10 | | -WEALTH_GROUP_URL = "https://headev.fews.net/api/wealthgroupcharacteristicvalue/" |
11 | | - |
12 | | -# Fetch and prepare data |
13 | | -livelihood_data = fetch_data(LIVELIHOOD_STRATEGY_URL) |
14 | | -wealth_group_data = fetch_data(WEALTH_GROUP_URL) |
15 | | - |
16 | | -livelihood_data = prepare_livelihood_data(livelihood_data) |
17 | | -wealth_group_data = prepare_wealth_group_data(wealth_group_data) |
| 9 | +from .functions import clean_livelihood_data, clean_wealth_group_data |
18 | 10 |
|
19 | 11 | # Unique countries and livelihood zones for dropdowns |
20 | | -unique_countries = sorted(livelihood_data["country_code"].unique()) |
21 | | -unique_zones = sorted(livelihood_data["livelihood_zone"].unique()) |
| 12 | +unique_countries = sorted(clean_livelihood_data["country_code"].dropna().unique()) |
| 13 | +unique_zones = sorted(clean_livelihood_data["livelihood_zone_baseline_label"].dropna().unique()) |
| 14 | + |
| 15 | +logger = logging.getLogger(__name__) |
22 | 16 |
|
23 | 17 | # Dash app |
24 | | -app = DjangoDash("Inventory_dashboard") |
| 18 | +app = DjangoDash( |
| 19 | + "Inventory_dashboard", |
| 20 | + suppress_callback_exceptions=True, |
| 21 | + external_stylesheets=[dbc.themes.BOOTSTRAP] |
| 22 | + ) |
25 | 23 | app.title = "HEA Dashboard" |
26 | 24 |
|
27 | 25 | # Layout |
28 | 26 | app.layout = html.Div( |
29 | 27 | [ |
30 | 28 | html.H1("HEA Data Inventory Dashboard", style={"textAlign": "center"}), |
31 | | - dcc.Dropdown( |
32 | | - id="country-dropdown", |
33 | | - options=[{"label": country, "value": country} for country in unique_countries], |
34 | | - placeholder="Select Country", |
35 | | - multi=False, |
36 | | - ), |
37 | | - dcc.Dropdown( |
38 | | - id="livelihood-zone-dropdown", |
39 | | - options=[{"label": zone, "value": zone} for zone in unique_zones], |
40 | | - placeholder="Select Livelihood Zone(s)", |
41 | | - multi=True, |
| 29 | + html.Div( |
| 30 | + [ |
| 31 | + html.Div( |
| 32 | + [ |
| 33 | + dcc.Dropdown( |
| 34 | + id="country-dropdown", |
| 35 | + options=[{"label": country, "value": country} for country in unique_countries], |
| 36 | + placeholder="Select Country(s)", |
| 37 | + multi=True, |
| 38 | + ), |
| 39 | + ], |
| 40 | + style={"flex": "1", "marginRight": "10px"}, # Set flex and spacing |
| 41 | + ), |
| 42 | + html.Div( |
| 43 | + [ |
| 44 | + dcc.Dropdown( |
| 45 | + id="livelihood-zone-dropdown", |
| 46 | + options=[{"label": zone, "value": zone} for zone in unique_zones], |
| 47 | + placeholder="Select Livelihood Zone(s)", |
| 48 | + multi=True, |
| 49 | + ), |
| 50 | + ], |
| 51 | + style={"flex": "1"}, |
| 52 | + ), |
| 53 | + ], |
| 54 | + style={ |
| 55 | + "display": "flex", |
| 56 | + "width": "100%", |
| 57 | + "justifyContent": "space-between", |
| 58 | + "marginBottom": "20px", |
| 59 | + }, |
42 | 60 | ), |
43 | 61 | html.Div( |
44 | 62 | [ |
45 | | - html.Div(dcc.Graph(id="wealth-chart"), style={"width": "48%", "display": "inline-block"}), |
46 | | - html.Div(dcc.Graph(id="livelihood-chart"), style={"width": "48%", "display": "inline-block"}), |
47 | | - ] |
| 63 | + html.Div( |
| 64 | + dcc.Graph(id="wealth-chart"), |
| 65 | + style={"width": "30%", "display": "inline-block"}, |
| 66 | + ), |
| 67 | + html.Div( |
| 68 | + dcc.Graph(id="livelihood-chart"), |
| 69 | + style={"width": "30%", "display": "inline-block"}, |
| 70 | + ), |
| 71 | + html.Div( |
| 72 | + dcc.Graph(id="wealth-monthly-chart"), |
| 73 | + style={"width": "30%", "display": "inline-block"}, |
| 74 | + ), |
| 75 | + ], |
48 | 76 | ), |
49 | 77 | html.Div( |
50 | 78 | [ |
51 | 79 | html.H3("Data Table", style={"textAlign": "center"}), |
52 | 80 | dash_table.DataTable( |
53 | 81 | id="data-table", |
54 | 82 | columns=[ |
55 | | - {"name": "Livelihood Zone", "id": "livelihood_zone"}, |
| 83 | + {"name": "Livelihood Zone", "id": "livelihood_zone_baseline_label"}, |
56 | 84 | {"name": "Strategy Type Count", "id": "Count"}, |
57 | 85 | {"name": "Wealth Characteristics Count", "id": "Wealth Characteristics Count"}, |
58 | 86 | ], |
59 | 87 | style_table={"overflowX": "auto"}, |
60 | 88 | style_cell={"textAlign": "left"}, |
61 | | - page_size=10, |
| 89 | + page_size=12, |
62 | 90 | ), |
63 | | - ] |
| 91 | + ], |
| 92 | + className="inventory-filter inventory-filter-last", |
64 | 93 | ), |
65 | | - ] |
| 94 | + ], |
| 95 | + className="div-wrapper control-panel-wrapper", |
66 | 96 | ) |
67 | 97 |
|
68 | 98 |
|
|
72 | 102 | Output("livelihood-zone-dropdown", "options"), |
73 | 103 | Output("wealth-chart", "figure"), |
74 | 104 | Output("livelihood-chart", "figure"), |
| 105 | + Output("wealth-monthly-chart", "figure"), |
75 | 106 | Output("data-table", "data"), |
76 | 107 | ], |
77 | 108 | [Input("country-dropdown", "value"), Input("livelihood-zone-dropdown", "value")], |
78 | 109 | ) |
79 | | -def update_charts(selected_country, selected_zones): |
80 | | - # Filter data based on selected country |
81 | | - if selected_country: |
82 | | - filtered_livelihood = livelihood_data[livelihood_data["country_code"] == selected_country] |
83 | | - filtered_wealth = wealth_group_data[wealth_group_data["country_code"] == selected_country] |
84 | | - filtered_zones = sorted(filtered_livelihood["livelihood_zone"].unique()) |
| 110 | +def update_charts(selected_countries, selected_zones): |
| 111 | + # Handle multi-country selection |
| 112 | + if selected_countries: |
| 113 | + filtered_livelihood = clean_livelihood_data[clean_livelihood_data["country_code"].isin(selected_countries)] |
| 114 | + filtered_wealth = clean_wealth_group_data[clean_wealth_group_data["country_code"].isin(selected_countries)] |
| 115 | + filtered_zones = sorted(filtered_livelihood["livelihood_zone_baseline_label"].unique()) |
85 | 116 | else: |
86 | | - filtered_livelihood = livelihood_data |
87 | | - filtered_wealth = wealth_group_data |
| 117 | + filtered_livelihood = clean_livelihood_data |
| 118 | + filtered_wealth = clean_wealth_group_data |
88 | 119 | filtered_zones = unique_zones |
89 | 120 |
|
90 | 121 | # Update options for livelihood zone dropdown |
91 | 122 | zone_options = [{"label": zone, "value": zone} for zone in filtered_zones] |
92 | 123 |
|
93 | 124 | # Filter data based on selected livelihood zones |
94 | 125 | if selected_zones: |
95 | | - filtered_livelihood = filtered_livelihood[filtered_livelihood["livelihood_zone"].isin(selected_zones)] |
96 | | - filtered_wealth = filtered_wealth[filtered_wealth["livelihood_zone"].isin(selected_zones)] |
| 126 | + filtered_livelihood = filtered_livelihood[filtered_livelihood["livelihood_zone_baseline_label"].isin(selected_zones)] |
| 127 | + filtered_wealth = filtered_wealth[filtered_wealth["livelihood_zone_baseline_label"].isin(selected_zones)] |
97 | 128 |
|
98 | 129 | # Group data for charts |
99 | 130 | livelihood_grouped = ( |
100 | | - filtered_livelihood.groupby(["livelihood_zone", "strategy_type_label"]).size().reset_index(name="Count") |
| 131 | + filtered_livelihood.groupby(["livelihood_zone_baseline_label", "strategy_type_label"]).size().reset_index(name="Count") |
| 132 | + ) |
| 133 | + wealth_grouped = filtered_wealth.groupby("livelihood_zone_baseline_label").size().reset_index(name="Wealth Characteristics Count") |
| 134 | + wealth_monthly_grouped = ( |
| 135 | + filtered_wealth.groupby(["created_month", "livelihood_zone_baseline_label"]).size().reset_index(name="Wealth Characteristics Count") |
101 | 136 | ) |
102 | | - wealth_grouped = filtered_wealth.groupby("livelihood_zone").size().reset_index(name="Wealth Characteristics Count") |
103 | 137 |
|
104 | 138 | wealth_fig = px.bar( |
105 | 139 | wealth_grouped, |
106 | | - x="livelihood_zone", |
| 140 | + x="livelihood_zone_baseline_label", |
107 | 141 | y="Wealth Characteristics Count", |
108 | 142 | title="Wealth Characteristics per Baseline", |
109 | | - labels={"livelihood_zone": "Baseline", "Wealth Characteristics Count": "Count"}, |
| 143 | + labels={"livelihood_zone_baseline_label": "Baseline", "Wealth Characteristics Count": "No. of Wealth Characteristics"}, |
110 | 144 | ) |
111 | 145 |
|
112 | 146 | livelihood_fig = px.bar( |
113 | 147 | livelihood_grouped, |
114 | 148 | x="strategy_type_label", |
115 | 149 | y="Count", |
116 | | - color="livelihood_zone", |
| 150 | + color="livelihood_zone_baseline_label", |
117 | 151 | title="Livelihood Strategies per Baseline", |
118 | | - labels={"strategy_type_label": "Strategy Type", "Count": "Count", "livelihood_zone": "Baseline"}, |
| 152 | + labels={"strategy_type_label": "Strategy Type", "Count": "No. of Livelihood Strategies", "livelihood_zone_baseline_label": "Baseline"}, |
119 | 153 | ) |
120 | 154 |
|
121 | | - return zone_options, wealth_fig, livelihood_fig, livelihood_grouped.to_dict("records") |
| 155 | + # Stacked/multiple column chart for wealth characteristics by month |
| 156 | + wealth_monthly_fig = px.bar( |
| 157 | + wealth_monthly_grouped, |
| 158 | + x="created_month", |
| 159 | + y="Wealth Characteristics Count", |
| 160 | + color="livelihood_zone_baseline_label", |
| 161 | + barmode="stack", # Use 'group' for multiple column chart |
| 162 | + title="Wealth Characteristics by Month and Baseline", |
| 163 | + labels={ |
| 164 | + "created_month": "Month", |
| 165 | + "Wealth Characteristics Count": "No. of Wealth Characteristics", |
| 166 | + "livelihood_zone_baseline_label": "Baseline", |
| 167 | + }, |
| 168 | + ) |
122 | 169 |
|
| 170 | + return zone_options, wealth_fig, livelihood_fig, wealth_monthly_fig, livelihood_grouped.to_dict("records") |
123 | 171 |
|
124 | 172 | # Run the app |
125 | 173 | if __name__ == "__main__": |
|
0 commit comments