Skip to content

Commit

Permalink
HEA-592 Inital setup;app may fail
Browse files Browse the repository at this point in the history
  • Loading branch information
enjoki committed Dec 30, 2024
1 parent 34feecd commit a26a3c5
Show file tree
Hide file tree
Showing 31 changed files with 1,890 additions and 1 deletion.
9 changes: 9 additions & 0 deletions apps/viz/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# viz/apps.py
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _


class VizConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "viz"
verbose_name = _("viz")
Empty file.
126 changes: 126 additions & 0 deletions apps/viz/dash/inventory_dashboard/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import plotly.express as px
from dash import dash_table, dcc, html
from dash.dependencies import Input, Output
from django_plotly_dash import DjangoDash

from .functions import fetch_data, prepare_livelihood_data, prepare_wealth_group_data

# API Endpoints
LIVELIHOOD_STRATEGY_URL = "https://headev.fews.net/api/livelihoodstrategy/"
WEALTH_GROUP_URL = "https://headev.fews.net/api/wealthgroupcharacteristicvalue/"

# Fetch and prepare data
livelihood_data = fetch_data(LIVELIHOOD_STRATEGY_URL)
wealth_group_data = fetch_data(WEALTH_GROUP_URL)

livelihood_data = prepare_livelihood_data(livelihood_data)
wealth_group_data = prepare_wealth_group_data(wealth_group_data)

# Unique countries and livelihood zones for dropdowns
unique_countries = sorted(livelihood_data["country_code"].unique())
unique_zones = sorted(livelihood_data["livelihood_zone"].unique())

# Dash app
app = DjangoDash("Inventory_dashboard")
app.title = "HEA Dashboard"

# Layout
app.layout = html.Div(
[
html.H1("HEA Data Inventory Dashboard", style={"textAlign": "center"}),
dcc.Dropdown(
id="country-dropdown",
options=[{"label": country, "value": country} for country in unique_countries],
placeholder="Select Country",
multi=False,
),
dcc.Dropdown(
id="livelihood-zone-dropdown",
options=[{"label": zone, "value": zone} for zone in unique_zones],
placeholder="Select Livelihood Zone(s)",
multi=True,
),
html.Div(
[
html.Div(dcc.Graph(id="wealth-chart"), style={"width": "48%", "display": "inline-block"}),
html.Div(dcc.Graph(id="livelihood-chart"), style={"width": "48%", "display": "inline-block"}),
]
),
html.Div(
[
html.H3("Data Table", style={"textAlign": "center"}),
dash_table.DataTable(
id="data-table",
columns=[
{"name": "Livelihood Zone", "id": "livelihood_zone"},
{"name": "Strategy Type Count", "id": "Count"},
{"name": "Wealth Characteristics Count", "id": "Wealth Characteristics Count"},
],
style_table={"overflowX": "auto"},
style_cell={"textAlign": "left"},
page_size=10,
),
]
),
]
)


# Callbacks
@app.callback(
[
Output("livelihood-zone-dropdown", "options"),
Output("wealth-chart", "figure"),
Output("livelihood-chart", "figure"),
Output("data-table", "data"),
],
[Input("country-dropdown", "value"), Input("livelihood-zone-dropdown", "value")],
)
def update_charts(selected_country, selected_zones):
# Filter data based on selected country
if selected_country:
filtered_livelihood = livelihood_data[livelihood_data["country_code"] == selected_country]
filtered_wealth = wealth_group_data[wealth_group_data["country_code"] == selected_country]
filtered_zones = sorted(filtered_livelihood["livelihood_zone"].unique())
else:
filtered_livelihood = livelihood_data
filtered_wealth = wealth_group_data
filtered_zones = unique_zones

# Update options for livelihood zone dropdown
zone_options = [{"label": zone, "value": zone} for zone in filtered_zones]

# Filter data based on selected livelihood zones
if selected_zones:
filtered_livelihood = filtered_livelihood[filtered_livelihood["livelihood_zone"].isin(selected_zones)]
filtered_wealth = filtered_wealth[filtered_wealth["livelihood_zone"].isin(selected_zones)]

# Group data for charts
livelihood_grouped = (
filtered_livelihood.groupby(["livelihood_zone", "strategy_type_label"]).size().reset_index(name="Count")
)
wealth_grouped = filtered_wealth.groupby("livelihood_zone").size().reset_index(name="Wealth Characteristics Count")

wealth_fig = px.bar(
wealth_grouped,
x="livelihood_zone",
y="Wealth Characteristics Count",
title="Wealth Characteristics per Baseline",
labels={"livelihood_zone": "Baseline", "Wealth Characteristics Count": "Count"},
)

livelihood_fig = px.bar(
livelihood_grouped,
x="strategy_type_label",
y="Count",
color="livelihood_zone",
title="Livelihood Strategies per Baseline",
labels={"strategy_type_label": "Strategy Type", "Count": "Count", "livelihood_zone": "Baseline"},
)

return zone_options, wealth_fig, livelihood_fig, livelihood_grouped.to_dict("records")


# Run the app
if __name__ == "__main__":
app.run_server(debug=True)
34 changes: 34 additions & 0 deletions apps/viz/dash/inventory_dashboard/functions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import pandas as pd
import requests


def fetch_data(api_url):
"""
Fetch data from the given API endpoint and return as a Pandas DataFrame.
"""
try:
response = requests.get(api_url)
response.raise_for_status()
data = response.json()
return pd.DataFrame(data)
except Exception as e:
print(f"Error fetching data: {e}")
return pd.DataFrame()


def prepare_livelihood_data(df):
"""
Prepare livelihood strategy data for visualization.
"""
df.rename(columns={"livelihood_zone_country": "country_code"}, inplace=True)
df["ls_baseline_date"] = df["livelihood_zone_baseline_label"].str.split(": ").str[1]
df["ls_baseline_month"] = pd.to_datetime(df["ls_baseline_date"], errors="coerce").dt.month_name()
return df


def prepare_wealth_group_data(df):
"""
Prepare wealth group data for visualization.
"""
df.rename(columns={"livelihood_zone_country_code": "country_code"}, inplace=True)
return df
16 changes: 16 additions & 0 deletions apps/viz/dash_wrapper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from django_plotly_dash import DjangoDash


class SecureDjangoDash(DjangoDash):
"""
An extended version of DjangoDash that allows fine-grained control of permissions
and clickjacking protection
"""

xframe_options = "DENY" # None (i.e. Allow) or SAMEORIGIN or DENY
login_required = True
permission_required = None

def __init__(self, *args, **kwargs):
self.permission_required = kwargs.pop("permission_required", None)
super().__init__(*args, **kwargs)
Loading

0 comments on commit a26a3c5

Please sign in to comment.