Skip to content

Commit fa0a1bb

Browse files
authored
Merge pull request #277 from cmu-delphi/development
Removed caching, made table stats async
2 parents 8c15f67 + 9e64f47 commit fa0a1bb

File tree

4 files changed

+125
-91
lines changed

4 files changed

+125
-91
lines changed

src/indicatorsets/urls.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from django.urls import path
22
from django.urls.resolvers import URLPattern
33
from indicatorsets.views import (IndicatorSetListView, epivis,
4-
generate_export_data_url, preview_data, create_query_code, get_available_geos)
4+
generate_export_data_url, preview_data, create_query_code, get_available_geos, get_related_indicators_json)
55

66
urlpatterns: list[URLPattern] = [
77
path("", IndicatorSetListView.as_view(), name="indicatorsets"),
@@ -10,4 +10,5 @@
1010
path("preview_data/", preview_data, name="preview_data"),
1111
path("create_query_code/", create_query_code, name="create_query_code"),
1212
path("get_available_geos/", get_available_geos, name="get_available_geos"),
13+
path("get_related_indicators/", get_related_indicators_json, name="get_related_indicators"),
1314
]

src/indicatorsets/utils.py

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
import requests
88
from django.conf import settings
9-
from django.core.cache import cache
109
from django.http import JsonResponse
1110
from epiweeks import Week
1211
from delphi_utils import get_structured_logger
@@ -815,18 +814,14 @@ def get_num_locations_from_meta(indicators):
815814
indicators = set(
816815
(indicator["source"], indicator["name"]) for indicator in indicators
817816
)
818-
metadata = cache.get("covidcast_meta")
819-
if metadata is None:
820-
try:
821-
metadata = requests.get(
822-
f"{settings.EPIDATA_URL}covidcast_meta/", timeout=5
823-
).json()["epidata"]
824-
# Cache for 24 hours
825-
cache.set("covidcast_meta", metadata, 60 * 60 * 24)
826-
except Exception as e:
827-
print(f"Error fetching covidcast metadata: {e}")
828-
return 0
829-
for r in metadata:
830-
if (r["data_source"], r["signal"]) in indicators:
831-
timeseries_count += r["num_locations"]
817+
try:
818+
metadata = requests.get(
819+
f"{settings.EPIDATA_URL}covidcast_meta/", timeout=5
820+
).json()["epidata"]
821+
for r in metadata:
822+
if (r["data_source"], r["signal"]) in indicators:
823+
timeseries_count += r["num_locations"]
824+
except Exception as e:
825+
print(f"Error fetching covidcast metadata: {e}")
826+
return 0
832827
return timeseries_count

src/indicatorsets/views.py

Lines changed: 81 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,61 @@
5050
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."
5151

5252

53+
def get_related_indicators(queryset, indicator_set_ids: list):
54+
related_indicators = []
55+
for indicator in queryset.filter(indicator_set__id__in=indicator_set_ids):
56+
related_indicators.append(
57+
{
58+
"id": indicator.id,
59+
"display_name": (
60+
indicator.get_display_name if indicator.get_display_name else ""
61+
),
62+
"member_name": (
63+
indicator.member_name if indicator.member_name else ""
64+
),
65+
"member_short_name": (
66+
indicator.member_short_name
67+
if indicator.member_short_name
68+
else ""
69+
),
70+
"name": indicator.name if indicator.name else "",
71+
"indicator_set": (
72+
indicator.indicator_set.id if indicator.indicator_set else ""
73+
),
74+
"indicator_set_name": (
75+
indicator.indicator_set.name if indicator.indicator_set else ""
76+
),
77+
"indicator_set_short_name": (
78+
indicator.indicator_set.short_name
79+
if indicator.indicator_set
80+
else ""
81+
),
82+
"endpoint": (
83+
indicator.indicator_set.epidata_endpoint
84+
if indicator.indicator_set
85+
else ""
86+
),
87+
"source": indicator.source.name if indicator.source else "",
88+
"time_type": indicator.time_type if indicator.time_type else "",
89+
"description": (
90+
indicator.description if indicator.description else ""
91+
),
92+
"member_description": (
93+
indicator.member_description
94+
if indicator.member_description
95+
else indicator.description
96+
),
97+
"restricted": (
98+
indicator.indicator_set.dua_required
99+
if indicator.indicator_set
100+
else ""
101+
),
102+
"source_type": indicator.source_type,
103+
}
104+
)
105+
return related_indicators
106+
107+
53108
class IndicatorSetListView(ListView):
54109
model = IndicatorSet
55110
template_name = "indicatorsets/indicatorSets.html"
@@ -67,60 +122,6 @@ def get_queryset(self):
67122
indicatorsets_logger.error(f"Error fetching indicator sets: {e}")
68123
return IndicatorSet.objects.none()
69124

70-
def get_related_indicators(self, queryset, indicator_set_ids: list):
71-
related_indicators = []
72-
for indicator in queryset.filter(indicator_set__id__in=indicator_set_ids):
73-
related_indicators.append(
74-
{
75-
"id": indicator.id,
76-
"display_name": (
77-
indicator.get_display_name if indicator.get_display_name else ""
78-
),
79-
"member_name": (
80-
indicator.member_name if indicator.member_name else ""
81-
),
82-
"member_short_name": (
83-
indicator.member_short_name
84-
if indicator.member_short_name
85-
else ""
86-
),
87-
"name": indicator.name if indicator.name else "",
88-
"indicator_set": (
89-
indicator.indicator_set.id if indicator.indicator_set else ""
90-
),
91-
"indicator_set_name": (
92-
indicator.indicator_set.name if indicator.indicator_set else ""
93-
),
94-
"indicator_set_short_name": (
95-
indicator.indicator_set.short_name
96-
if indicator.indicator_set
97-
else ""
98-
),
99-
"endpoint": (
100-
indicator.indicator_set.epidata_endpoint
101-
if indicator.indicator_set
102-
else ""
103-
),
104-
"source": indicator.source.name if indicator.source else "",
105-
"time_type": indicator.time_type if indicator.time_type else "",
106-
"description": (
107-
indicator.description if indicator.description else ""
108-
),
109-
"member_description": (
110-
indicator.member_description
111-
if indicator.member_description
112-
else indicator.description
113-
),
114-
"restricted": (
115-
indicator.indicator_set.dua_required
116-
if indicator.indicator_set
117-
else ""
118-
),
119-
"source_type": indicator.source_type,
120-
}
121-
)
122-
return related_indicators
123-
124125
def get_url_params(self):
125126
url_params_dict = {
126127
"pathogens": (
@@ -244,14 +245,6 @@ def get_context_data(self, **kwargs):
244245
output_field=IntegerField(),
245246
),
246247
).order_by("beta_last", "-is_top_priority", "-delphi_hosted", "name")
247-
related_indicators = self.get_related_indicators(
248-
filter.indicators_qs.select_related("indicator_set", "source"),
249-
filter.qs.values_list("id", flat=True),
250-
)
251-
context["related_indicators"] = json.dumps(related_indicators)
252-
context["num_of_timeseries"] = get_num_locations_from_meta(
253-
related_indicators
254-
)
255248
context["filters_descriptions"] = (
256249
FilterDescription.get_all_descriptions_as_dict()
257250
)
@@ -540,3 +533,29 @@ def get_available_geos(request):
540533
return JsonResponse(
541534
{"geographic_granularities": geographic_granularities}, safe=False
542535
)
536+
537+
538+
def get_related_indicators_json(request):
539+
try:
540+
queryset = IndicatorSet.objects.all().prefetch_related(
541+
"geographic_scope",
542+
"pathogens",
543+
"severity_pyramid_rungs",
544+
"geographic_levels",
545+
)
546+
except Exception as e:
547+
indicatorsets_logger.error(f"Error fetching indicator sets: {e}")
548+
queryset = IndicatorSet.objects.none()
549+
550+
filter = IndicatorSetFilter(request.GET, queryset=queryset)
551+
related_indicators = get_related_indicators(
552+
filter.indicators_qs.select_related("indicator_set", "source"),
553+
filter.qs.values_list("id", flat=True),
554+
)
555+
num_of_timeseries = get_num_locations_from_meta(related_indicators)
556+
return JsonResponse(
557+
{
558+
"related_indicators": related_indicators,
559+
"num_of_timeseries": num_of_timeseries,
560+
}
561+
)

src/templates/indicatorsets/indicatorSetsTable.html

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -355,32 +355,54 @@
355355
<script src="{% static 'js/indicatorSetsTable.js' %}"></script>
356356
<script src="{% static 'js/pluralize_word.js' %}"></script>
357357
<script>
358-
var relatedIndicators = JSON.parse(JSON.stringify({{ related_indicators|safe }}));
359-
var numOfTimeseries = {{ num_of_timeseries }};
358+
var relatedIndicators = [];
359+
var numOfTimeseries = 0;
360360

361361
function numberWithCommas(x) {
362362
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
363363
}
364364

365-
366365
$(document).ready(function() {
367366
table.columns.adjust();
368367
const totalRowsSpan = document.createElement("span");
369368
totalRowsSpan.classList.add("table-stats-info");
370-
if (numOfTimeseries > 0) {
371-
totalRowsSpan.innerHTML = `Showing <b>${relatedIndicators.length}</b> distinct ${pluralize(relatedIndicators.length, 'indicator')} (arranged in <b>${table.page.info().recordsTotal}</b> ${pluralize(table.page.info().recordsTotal, 'set')}), including <b>${numberWithCommas(numOfTimeseries)}</b> Delphi-hosted time series across numerous locations.`;
372-
} else {
373-
totalRowsSpan.innerHTML = `Showing <b>${relatedIndicators.length}</b> distinct ${pluralize(relatedIndicators.length, 'indicator')} (arranged in <b>${table.page.info().recordsTotal}</b> ${pluralize(table.page.info().recordsTotal, 'set')}).`;
374-
}
369+
totalRowsSpan.innerHTML = "Loading indicators statistics...";
375370
const refElement = document.getElementById("indicatorSetsTable_wrapper");
376371
refElement.before(totalRowsSpan);
372+
373+
// Fetch related indicators asynchronously
374+
$.ajax({
375+
url: "{% url 'get_related_indicators' %}" + window.location.search,
376+
method: "GET",
377+
success: function(response) {
378+
relatedIndicators = response.related_indicators;
379+
numOfTimeseries = response.num_of_timeseries;
380+
381+
if (numOfTimeseries > 0) {
382+
totalRowsSpan.innerHTML = `Showing <b>${relatedIndicators.length}</b> distinct ${pluralize(relatedIndicators.length, 'indicator')} (arranged in <b>${table.page.info().recordsTotal}</b> ${pluralize(table.page.info().recordsTotal, 'set')}), including <b>${numberWithCommas(numOfTimeseries)}</b> Delphi-hosted time series across numerous locations.`;
383+
} else {
384+
totalRowsSpan.innerHTML = `Showing <b>${relatedIndicators.length}</b> distinct ${pluralize(relatedIndicators.length, 'indicator')} (arranged in <b>${table.page.info().recordsTotal}</b> ${pluralize(table.page.info().recordsTotal, 'set')}).`;
385+
}
386+
},
387+
error: function(xhr, status, error) {
388+
console.error("Error fetching related indicators:", error);
389+
totalRowsSpan.innerHTML = "Error loading indicators statistics.";
390+
}
391+
});
377392
});
378393

379394
// Add event listener for openizng and closing details
380395
$('#indicatorSetsTable tbody').on('click', 'td.dt-control', function () {
381396
var tr = $(this).closest('tr');
382397
var row = table.row(tr);
383-
398+
399+
if (relatedIndicators.length === 0) {
400+
// If data hasn't loaded yet, maybe wait or show alert?
401+
// For now, let's assume it loads fast enough or just show empty/loading in child row if we wanted to be fancy.
402+
// But existing behavior with empty array will just show "No available indicators yet." from format function.
403+
// We can check if request is pending if needed, but let's stick to simple first.
404+
}
405+
384406
if (row.child.isShown()) {
385407
// This row is already open - close it
386408
row.child.hide();
@@ -389,9 +411,6 @@
389411
// Open this row
390412
row.child(format(tr.data('id'), relatedIndicators, tr.data("description"))).show();
391413
}
392-
393-
});
394-
395-
396414

415+
});
397416
</script>

0 commit comments

Comments
 (0)