Skip to content

Commit a26a3c5

Browse files
committed
HEA-592 Inital setup;app may fail
1 parent 34feecd commit a26a3c5

31 files changed

+1890
-1
lines changed

apps/viz/apps.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# viz/apps.py
2+
from django.apps import AppConfig
3+
from django.utils.translation import gettext_lazy as _
4+
5+
6+
class VizConfig(AppConfig):
7+
default_auto_field = "django.db.models.BigAutoField"
8+
name = "viz"
9+
verbose_name = _("viz")

apps/viz/dash/inventory_dashboard/__init__.py

Whitespace-only changes.
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import plotly.express as px
2+
from dash import dash_table, dcc, html
3+
from dash.dependencies import Input, Output
4+
from django_plotly_dash import DjangoDash
5+
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)
18+
19+
# 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())
22+
23+
# Dash app
24+
app = DjangoDash("Inventory_dashboard")
25+
app.title = "HEA Dashboard"
26+
27+
# Layout
28+
app.layout = html.Div(
29+
[
30+
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,
42+
),
43+
html.Div(
44+
[
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+
]
48+
),
49+
html.Div(
50+
[
51+
html.H3("Data Table", style={"textAlign": "center"}),
52+
dash_table.DataTable(
53+
id="data-table",
54+
columns=[
55+
{"name": "Livelihood Zone", "id": "livelihood_zone"},
56+
{"name": "Strategy Type Count", "id": "Count"},
57+
{"name": "Wealth Characteristics Count", "id": "Wealth Characteristics Count"},
58+
],
59+
style_table={"overflowX": "auto"},
60+
style_cell={"textAlign": "left"},
61+
page_size=10,
62+
),
63+
]
64+
),
65+
]
66+
)
67+
68+
69+
# Callbacks
70+
@app.callback(
71+
[
72+
Output("livelihood-zone-dropdown", "options"),
73+
Output("wealth-chart", "figure"),
74+
Output("livelihood-chart", "figure"),
75+
Output("data-table", "data"),
76+
],
77+
[Input("country-dropdown", "value"), Input("livelihood-zone-dropdown", "value")],
78+
)
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())
85+
else:
86+
filtered_livelihood = livelihood_data
87+
filtered_wealth = wealth_group_data
88+
filtered_zones = unique_zones
89+
90+
# Update options for livelihood zone dropdown
91+
zone_options = [{"label": zone, "value": zone} for zone in filtered_zones]
92+
93+
# Filter data based on selected livelihood zones
94+
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)]
97+
98+
# Group data for charts
99+
livelihood_grouped = (
100+
filtered_livelihood.groupby(["livelihood_zone", "strategy_type_label"]).size().reset_index(name="Count")
101+
)
102+
wealth_grouped = filtered_wealth.groupby("livelihood_zone").size().reset_index(name="Wealth Characteristics Count")
103+
104+
wealth_fig = px.bar(
105+
wealth_grouped,
106+
x="livelihood_zone",
107+
y="Wealth Characteristics Count",
108+
title="Wealth Characteristics per Baseline",
109+
labels={"livelihood_zone": "Baseline", "Wealth Characteristics Count": "Count"},
110+
)
111+
112+
livelihood_fig = px.bar(
113+
livelihood_grouped,
114+
x="strategy_type_label",
115+
y="Count",
116+
color="livelihood_zone",
117+
title="Livelihood Strategies per Baseline",
118+
labels={"strategy_type_label": "Strategy Type", "Count": "Count", "livelihood_zone": "Baseline"},
119+
)
120+
121+
return zone_options, wealth_fig, livelihood_fig, livelihood_grouped.to_dict("records")
122+
123+
124+
# Run the app
125+
if __name__ == "__main__":
126+
app.run_server(debug=True)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import pandas as pd
2+
import requests
3+
4+
5+
def fetch_data(api_url):
6+
"""
7+
Fetch data from the given API endpoint and return as a Pandas DataFrame.
8+
"""
9+
try:
10+
response = requests.get(api_url)
11+
response.raise_for_status()
12+
data = response.json()
13+
return pd.DataFrame(data)
14+
except Exception as e:
15+
print(f"Error fetching data: {e}")
16+
return pd.DataFrame()
17+
18+
19+
def prepare_livelihood_data(df):
20+
"""
21+
Prepare livelihood strategy data for visualization.
22+
"""
23+
df.rename(columns={"livelihood_zone_country": "country_code"}, inplace=True)
24+
df["ls_baseline_date"] = df["livelihood_zone_baseline_label"].str.split(": ").str[1]
25+
df["ls_baseline_month"] = pd.to_datetime(df["ls_baseline_date"], errors="coerce").dt.month_name()
26+
return df
27+
28+
29+
def prepare_wealth_group_data(df):
30+
"""
31+
Prepare wealth group data for visualization.
32+
"""
33+
df.rename(columns={"livelihood_zone_country_code": "country_code"}, inplace=True)
34+
return df

apps/viz/dash_wrapper.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from django_plotly_dash import DjangoDash
2+
3+
4+
class SecureDjangoDash(DjangoDash):
5+
"""
6+
An extended version of DjangoDash that allows fine-grained control of permissions
7+
and clickjacking protection
8+
"""
9+
10+
xframe_options = "DENY" # None (i.e. Allow) or SAMEORIGIN or DENY
11+
login_required = True
12+
permission_required = None
13+
14+
def __init__(self, *args, **kwargs):
15+
self.permission_required = kwargs.pop("permission_required", None)
16+
super().__init__(*args, **kwargs)

0 commit comments

Comments
 (0)