Skip to content

Commit 57b8174

Browse files
authored
Merge pull request #230 from cmu-delphi/development
Fixed chart
2 parents 8aade3a + 059905c commit 57b8174

File tree

5 files changed

+1072
-830
lines changed

5 files changed

+1072
-830
lines changed

src/alternative_interface/urls.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
from django.urls import path
22
from django.urls.resolvers import URLPattern
3-
from alternative_interface.views import alternative_interface_view
3+
from alternative_interface.views import (
4+
alternative_interface_view,
5+
get_available_geos_ajax,
6+
get_chart_data_ajax,
7+
)
48

59
urlpatterns: list[URLPattern] = [
610
path("alternative_interface", alternative_interface_view, name="alternative_interface"),
11+
path("api/get_available_geos", get_available_geos_ajax, name="get_available_geos_ajax"),
12+
path("api/get_chart_data", get_chart_data_ajax, name="get_chart_data_ajax"),
713
]

src/alternative_interface/views.py

Lines changed: 104 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1-
from django.shortcuts import render
1+
import logging
2+
23
from django.db.models import Case, When, Value, IntegerField
3-
from alternative_interface.models import ExpressViewIndicator
4-
from epiportal.settings import ALTERNATIVE_INTERFACE_VERSION
4+
from django.http import JsonResponse
5+
from django.shortcuts import render
56

7+
from alternative_interface.models import ExpressViewIndicator
68
from alternative_interface.utils import get_available_geos, get_chart_data
9+
from epiportal.settings import ALTERNATIVE_INTERFACE_VERSION
710

11+
logger = logging.getLogger(__name__)
812

913
MENU_ITEMS_DISPLAY_ORDER_NUMBER = {
1014
"Influenza": 1,
@@ -13,21 +17,53 @@
1317
"Influenza-Like Illness (ILI)": 4,
1418
}
1519

16-
HEADER_DESCRIPTION = "Discover, display and download real-time infectious disease indicators (time series) that track a variety of pathogens, diseases and syndromes in a variety of locations (primarily within the USA). Browse the list, or filter it first by locations and pathogens of interest, by surveillance categories, and more. Expand any row to expose and select from a set of related indicators, then hit 'Show Selected Indicators' at bottom to plot or export your selected indicators, or to generate code snippets to retrieve them from the Delphi Epidata API. Most indicators are served from the Delphi Epidata real-time repository, but some may be available only from third parties or may require prior approval."
20+
21+
def _convert_indicators_to_dicts(indicators_qs):
22+
"""Convert queryset of ExpressViewIndicator to list of dictionaries."""
23+
return [
24+
{
25+
"_endpoint": (
26+
indicator.indicator.indicator_set.epidata_endpoint
27+
if indicator.indicator.indicator_set
28+
else ""
29+
),
30+
"name": indicator.indicator.name,
31+
"data_source": (
32+
indicator.indicator.source.name
33+
if indicator.indicator.source
34+
else "Unknown"
35+
),
36+
"time_type": indicator.indicator.time_type,
37+
"indicator_set_short_name": (
38+
indicator.indicator.indicator_set.short_name
39+
if indicator.indicator.indicator_set
40+
else "Unknown"
41+
),
42+
"member_short_name": (
43+
indicator.indicator.member_short_name
44+
if indicator.indicator.member_short_name
45+
else "Unknown"
46+
),
47+
}
48+
for indicator in indicators_qs
49+
]
50+
51+
52+
def _get_indicators_queryset(pathogen_filter):
53+
"""Get optimized queryset for indicators filtered by pathogen."""
54+
return (
55+
ExpressViewIndicator.objects.filter(menu_item=pathogen_filter)
56+
.select_related("indicator__indicator_set", "indicator__source")
57+
)
1758

1859

1960
def alternative_interface_view(request):
61+
"""Main view for the alternative interface dashboard."""
2062
try:
21-
ctx = {}
22-
ctx["header_description"] = HEADER_DESCRIPTION
23-
ctx["alternative_interface_version"] = ALTERNATIVE_INTERFACE_VERSION
24-
# Get filters from URL parameters
2563
pathogen_filter = request.GET.get("pathogen", "")
2664
geography_filter = request.GET.get("geography", "")
27-
ctx["selected_pathogen"] = pathogen_filter
28-
ctx["selected_geography"] = geography_filter
2965

30-
# Fetch pathogens for dropdown
66+
# Fetch pathogens for dropdown - optimized query
3167
pathogens_qs = (
3268
ExpressViewIndicator.objects.annotate(
3369
order_number=Case(
@@ -44,51 +80,65 @@ def alternative_interface_view(request):
4480
.order_by("order_number")
4581
)
4682
pathogens = [item["menu_item"] for item in pathogens_qs]
47-
ctx["pathogens"] = pathogens
48-
49-
indicators_qs = ExpressViewIndicator.objects.filter(
50-
menu_item=pathogen_filter
51-
).prefetch_related("indicator")
52-
53-
# Convert to list of dictionaries
54-
ctx["indicators"] = [
55-
{
56-
"_endpoint": (
57-
indicator.indicator.indicator_set.epidata_endpoint
58-
if indicator.indicator.indicator_set
59-
else ""
60-
),
61-
"name": indicator.indicator.name,
62-
"data_source": (
63-
indicator.indicator.source.name
64-
if indicator.indicator.source
65-
else "Unknown"
66-
),
67-
"time_type": indicator.indicator.time_type,
68-
"indicator_set_short_name": (
69-
indicator.indicator.indicator_set.short_name
70-
if indicator.indicator.indicator_set
71-
else "Unknown"
72-
),
73-
"member_short_name": (
74-
indicator.indicator.member_short_name
75-
if indicator.indicator.member_short_name
76-
else "Unknown"
77-
),
78-
}
79-
for indicator in indicators_qs
80-
]
81-
82-
ctx["available_geos"] = get_available_geos(ctx["indicators"])
83-
84-
if geography_filter:
85-
ctx["chart_data"] = get_chart_data(ctx["indicators"], geography_filter)
86-
else:
87-
ctx["chart_data"] = []
83+
84+
# Get indicators with optimized query
85+
indicators_qs = _get_indicators_queryset(pathogen_filter)
86+
indicators = _convert_indicators_to_dicts(indicators_qs)
87+
88+
ctx = {
89+
"alternative_interface_version": ALTERNATIVE_INTERFACE_VERSION,
90+
"selected_pathogen": pathogen_filter,
91+
"selected_geography": geography_filter,
92+
"pathogens": pathogens,
93+
"indicators": indicators,
94+
"available_geos": get_available_geos(indicators),
95+
"chart_data": (
96+
get_chart_data(indicators, geography_filter)
97+
if geography_filter
98+
else []
99+
),
100+
}
101+
88102
return render(
89103
request, "alternative_interface/alter_dashboard.html", context=ctx
90104
)
91105
except Exception as e:
92-
from django.http import HttpResponse
106+
logger.exception("Error loading alternative interface page")
107+
return JsonResponse({"error": str(e)}, status=500)
108+
93109

94-
return HttpResponse(f"Error loading page: {str(e)}")
110+
def get_available_geos_ajax(request):
111+
"""AJAX endpoint to get available geographies for a selected pathogen."""
112+
try:
113+
pathogen_filter = request.GET.get("pathogen", "")
114+
115+
if not pathogen_filter:
116+
return JsonResponse({"available_geos": []})
117+
118+
indicators_qs = _get_indicators_queryset(pathogen_filter)
119+
indicators = _convert_indicators_to_dicts(indicators_qs)
120+
available_geos = get_available_geos(indicators)
121+
122+
return JsonResponse({"available_geos": available_geos})
123+
except Exception as e:
124+
logger.exception("Error fetching available geos")
125+
return JsonResponse({"error": str(e)}, status=500)
126+
127+
128+
def get_chart_data_ajax(request):
129+
"""AJAX endpoint to get chart data for selected pathogen and geography."""
130+
try:
131+
pathogen_filter = request.GET.get("pathogen", "")
132+
geography_filter = request.GET.get("geography", "")
133+
134+
if not pathogen_filter or not geography_filter:
135+
return JsonResponse({"chart_data": {}})
136+
137+
indicators_qs = _get_indicators_queryset(pathogen_filter)
138+
indicators = _convert_indicators_to_dicts(indicators_qs)
139+
chart_data = get_chart_data(indicators, geography_filter)
140+
141+
return JsonResponse({"chart_data": chart_data})
142+
except Exception as e:
143+
logger.exception("Error fetching chart data")
144+
return JsonResponse({"error": str(e)}, status=500)

0 commit comments

Comments
 (0)