From da14316b3e5e19270832682e956efd88a28096da Mon Sep 17 00:00:00 2001 From: chejennifer <69875368+chejennifer@users.noreply.github.com> Date: Thu, 17 Sep 2020 15:14:40 -0700 Subject: [PATCH] append state code to place names when applicable (#413) * append state code to place names when applicable * address pr comments * fix comment Co-authored-by: beets --- server/routes/api/place.py | 169 ++++++++++++--- server/tests/api/place_test.py | 182 ---------------- server/tests/api_place_test.py | 287 ++++++++++++++++++++++++++ static/js/shared/data_fetcher.test.ts | 116 +++++++++++ static/js/shared/data_fetcher.ts | 21 +- static/js/tools/mock_functions.tsx | 8 + 6 files changed, 573 insertions(+), 210 deletions(-) delete mode 100644 server/tests/api/place_test.py create mode 100644 server/tests/api_place_test.py diff --git a/server/routes/api/place.py b/server/routes/api/place.py index a7e9469cd9..17a62f7757 100644 --- a/server/routes/api/place.py +++ b/server/routes/api/place.py @@ -60,6 +60,9 @@ 'UnemploymentRate_Person': 'Highest Unemployment Rate', } +STATE_EQUIVALENTS = {"State", "AdministrativeArea1"} +US_ISO_CODE_PREFIX = 'US' + # Define blueprint bp = Blueprint("api.place", __name__, url_prefix='/api/place') @@ -225,13 +228,19 @@ def child_fetch(dcid): @bp.route('/parent/') def api_parent_places(dcid): - return Response(parent_places(dcid), 200, mimetype='application/json') + result = parent_places(dcid)[dcid] + return Response(json.dumps(result), 200, mimetype='application/json') @cache.memoize(timeout=3600 * 24) # Cache for one day. -def parent_places(dcid): - """ - Get the parent place chain for a place. +def parent_places(dcids): + """ Get the parent place chain for a list of places. + + Args: + dcids: ^ separated string of dcids. It must be a single string for the cache. + + Returns: + A dictionary of lists of parent places, keyed by dcid. """ # In DataCommons knowledge graph, places has multiple containedInPlace # relation with parent places, but it might not be comprehensive. For @@ -239,36 +248,68 @@ def parent_places(dcid): # "California" but not "United States": # https://datacommons.org/browser/geoId/0649670 # Here calling get_parent_place twice to get to the top parents. - parents1 = get_parent_place(dcid) - if len(parents1) == 0: - return json.dumps([]) - parents2 = get_parent_place(parents1[-1]['dcid']) - parents1.extend(parents2) - if parents2: - parents3 = get_parent_place(parents2[-1]['dcid']) - parents1.extend(parents3) - ret = [x for x in parents1 if x['dcid'] != 'Earth'] - return json.dumps(ret) + result = {} + + parents1 = get_parent_place(dcids) + if not dcids: + return result + dcids = dcids.split('^') + dcid_parents1_mapping = {} + for dcid in dcids: + first_parents = parents1[dcid] + result[dcid] = first_parents + if first_parents: + dcid_parents1_mapping[dcid] = first_parents[-1]['dcid'] + + parents2 = get_parent_place('^'.join(dcid_parents1_mapping.values())) + dcid_parents2_mapping = {} + for dcid in dcid_parents1_mapping.keys(): + second_parents = parents2[dcid_parents1_mapping[dcid]] + result[dcid].extend(second_parents) + if second_parents: + dcid_parents2_mapping[dcid] = second_parents[-1]['dcid'] + + parents3 = get_parent_place('^'.join(dcid_parents2_mapping.values())) + for dcid in dcid_parents2_mapping.keys(): + result[dcid].extend(parents3[dcid_parents2_mapping[dcid]]) + result[dcid] = [x for x in result[dcid] if x['dcid'] != 'Earth'] + + return result @cache.memoize(timeout=3600 * 24) # Cache for one day. -def get_parent_place(dcid): +def get_parent_place(dcids): + """ Get containedInPlace for each place in a list of places + + Args: + dcids: ^ separated string of dcids. It must be a single string for the cache. + + Returns: + A dictionary of lists of containedInPlace, keyed by dcid. + """ + if dcids: + dcids = dcids.split('^') + else: + dcids = [] response = fetch_data('/node/property-values', { - 'dcids': [dcid], + 'dcids': dcids, 'property': 'containedInPlace', 'direction': 'out' }, compress=False, post=True) - parents = response[dcid].get('out', []) - parents.sort(key=lambda x: x['dcid'], reverse=True) - for i in range(len(parents)): - if len(parents[i]['types']) > 1: - parents[i]['types'] = [ - x for x in parents[i]['types'] - if not x.startswith('AdministrativeArea') - ] - return parents + result = {} + for dcid in dcids: + parents = response[dcid].get('out', []) + parents.sort(key=lambda x: x['dcid'], reverse=True) + for i in range(len(parents)): + if len(parents[i]['types']) > 1: + parents[i]['types'] = [ + x for x in parents[i]['types'] + if not x.startswith('AdministrativeArea') + ] + result[dcid] = parents + return result @cache.memoize(timeout=3600 * 24) # Cache for one day. @@ -345,7 +386,7 @@ def api_similar_places(stats_var, dcid): """ Get the similar places for a given place by stats var within the same place. """ - parents = json.loads(parent_places(dcid)) + parents = parent_places(dcid)[dcid] # scope similar places to the same country if possible parent_dcid = None if parents and len(parents): @@ -405,7 +446,7 @@ def api_ranking(dcid): Get the ranking information for a given place. """ current_place_type = get_place_type(dcid) - parents = json.loads(parent_places(dcid)) + parents = parent_places(dcid)[dcid] selected_parents = [] parent_names = {} for parent in parents: @@ -466,3 +507,77 @@ def api_ranking(dcid): result[label] = [x for x in result[label] if 'data' in x] result['label'] = [x for x in all_labels if x in result] return Response(json.dumps(result), 200, mimetype='application/json') + + +@cache.memoize(timeout=3600 * 24) # Cache for one day. +def get_state_code(dcids): + """Get state codes for a list of places that are state equivalents + + Args: + dcids: ^ separated string of dcids of places that are state equivalents + + Returns: + A dictionary of state codes, keyed by dcid + """ + result = {} + if not dcids: + return result + dcids = dcids.split('^') + iso_codes = dc.get_property_values(dcids, 'isoCode', True) + + for dcid in dcids: + state_code = None + iso_code = iso_codes[dcid] + if iso_code: + split_iso_code = iso_code[0].split("-") + if len(split_iso_code + ) > 1 and split_iso_code[0] == US_ISO_CODE_PREFIX: + state_code = split_iso_code[1] + result[dcid] = state_code + + return result + + +@cache.memoize(timeout=3600 * 24) # Cache for one day. +def get_display_name(dcids): + """ Get display names for a list of places. Display name is place name with state code + if it has a parent place that is a state. + + Args: + dcids: ^ separated string of dcids. It must be a single string for the cache. + + Returns: + A dictionary of display names, keyed by dcid. + """ + place_names = cached_name(dcids) + parents = parent_places(dcids) + dcids = dcids.split('^') + result = {} + dcid_state_mapping = {} + for dcid in dcids: + for parent_place in parents[dcid]: + parent_dcid = parent_place['dcid'] + place_types = parent_place['types'] + for place_type in place_types: + if place_type in STATE_EQUIVALENTS: + dcid_state_mapping[dcid] = parent_dcid + break + result[dcid] = place_names[dcid] + + state_codes = get_state_code('^'.join( + (sorted(dcid_state_mapping.values())))) + for dcid in dcid_state_mapping.keys(): + state_code = state_codes[dcid_state_mapping[dcid]] + if state_code: + result[dcid] = result[dcid] + ', ' + state_code + return result + + +@bp.route('/displayname') +def api_display_name(): + """ + Get display names for a list of places. + """ + dcids = request.args.getlist('dcid') + result = get_display_name('^'.join((sorted(dcids)))) + return Response(json.dumps(result), 200, mimetype='application/json') diff --git a/server/tests/api/place_test.py b/server/tests/api/place_test.py deleted file mode 100644 index 9c074e768c..0000000000 --- a/server/tests/api/place_test.py +++ /dev/null @@ -1,182 +0,0 @@ -# Copyright 2020 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import json -import unittest -from unittest.mock import patch - -from main import app - - -class TestRoute(unittest.TestCase): - - @patch('routes.api.place.fetch_data') - @patch('routes.api.place.get_stats_wrapper') - def test_index(self, mock_get_stats, mock_fetch_data): - mock_response = { - 'geoId/06': { - 'in': [{ - 'dcid': 'dcid1', - 'name': 'name1', - 'types': ['County', 'AdministrativeArea'], - }, { - 'dcid': 'dcid2', - 'name': 'name2', - 'types': ['County'], - }, { - 'dcid': 'dcid3', - 'name': 'name3', - 'types': ['State'], - }, { - 'dcid': 'dcid4', - 'name': 'name4', - 'types': ['CensusTract'], - }] - } - } - mock_fetch_data.side_effect = ( - lambda url, req, compress, post: mock_response) - - mock_get_stats.return_value = json.dumps({ - 'dcid1': { - 'data': { - '2018': 200 - } - }, - 'dcid2': { - 'data': { - '2018': 300 - } - }, - 'dcid3': { - 'data': { - '2018': 100 - } - }, - 'dcid4': { - 'data': { - '2018': 500 - } - }, - }) - - response = app.test_client().get('/api/place/child/geoId/06') - assert response.status_code == 200 - assert json.loads(response.data) == { - 'County': [{ - 'dcid': 'dcid2', - 'name': 'name2', - 'pop': 300 - }, { - 'dcid': 'dcid1', - 'name': 'name1', - 'pop': 200 - }], - 'State': [{ - 'dcid': 'dcid3', - 'name': 'name3', - 'pop': 100 - }] - } - - -class TestApiParentPlaces(unittest.TestCase): - - @staticmethod - def side_effect(url, req, compress, post): - if 'geoId/0649670' == req['dcids'][0]: - return { - 'geoId/0649670': { - 'out': [{ - 'dcid': 'geoId/06085', - 'name': 'Santa Clara County', - 'provenanceId': 'dc/sm3m2w3', - 'types': ['AdministrativeArea', 'County'] - }, { - 'dcid': 'geoId/06', - 'name': 'California', - 'provenanceId': 'dc/sm3m2w3', - 'types': ['AdministrativeArea', 'State'] - }] - } - } - elif 'geoId/06' == req['dcids'][0]: - return { - 'geoId/06': { - 'out': [{ - 'dcid': 'country/USA', - 'name': 'United States', - 'provenanceId': 'dc/sm3m2w3', - 'types': ['Country'] - }] - } - } - else: - return {req['dcids'][0]: {}} - - @patch('routes.api.place.fetch_data') - def test_parent_places(self, mock_fetch_data): - mock_fetch_data.side_effect = self.side_effect - response = app.test_client().get('/api/place/parent/geoId/0649670') - assert response.status_code == 200 - assert json.loads(response.data) == [{ - 'dcid': 'geoId/06085', - 'name': 'Santa Clara County', - 'provenanceId': 'dc/sm3m2w3', - 'types': ['County'] - }, { - 'dcid': 'geoId/06', - 'name': 'California', - 'provenanceId': 'dc/sm3m2w3', - 'types': ['State'] - }, { - 'dcid': 'country/USA', - 'name': 'United States', - 'provenanceId': 'dc/sm3m2w3', - 'types': ['Country'] - }] - - -class TestApiPlaceName(unittest.TestCase): - - @patch('routes.api.place.fetch_data') - def test_parent_places(self, mock_fetch_data): - mock_response = { - 'geoId/06': { - 'out': [{ - 'value': 'California', - 'provenance': 'prov1' - }] - }, - 'geoId/07': { - 'out': [] - }, - 'geoId/08': { - 'out': [{ - 'value': 'Colorado', - 'provenance': 'prov2' - }] - } - } - mock_fetch_data.side_effect = ( - lambda url, req, compress, post: mock_response) - - response = app.test_client().get( - '/api/place/name?dcid=geoId/06&dcid=geoId/07&dcid=geoId/08') - assert response.status_code == 200 - assert json.loads(response.data) == { - 'geoId/06': 'California', - 'geoId/07': '', - 'geoId/08': 'Colorado' - } diff --git a/server/tests/api_place_test.py b/server/tests/api_place_test.py new file mode 100644 index 0000000000..e7f3876fa1 --- /dev/null +++ b/server/tests/api_place_test.py @@ -0,0 +1,287 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json +import unittest +from unittest.mock import patch + +from main import app + + +class TestRoute(unittest.TestCase): + + @staticmethod + def side_effect(url, req, compress, post): + if 'containedInPlace' == req['property']: + return { + 'geoId/06': { + 'in': [{ + 'dcid': 'dcid1', + 'name': 'name1', + 'types': ['County', 'AdministrativeArea2'], + }, { + 'dcid': 'dcid2', + 'name': 'name2', + 'types': ['County'], + }, { + 'dcid': 'dcid4', + 'name': 'name4', + 'types': ['CensusTract'], + }] + } + } + elif 'geoOverlaps' == req['property']: + return { + 'geoId/06': { + 'in': [ + { + 'dcid': 'dcid3', + 'name': 'name3', + 'types': ['State'], + }, + { + 'dcid': 'dcid5', + 'name': 'name5', + 'types': ['AdministrativeArea2'], + }, + ] + } + } + else: + return {req['dcids'][0]: {}} + + @patch('routes.api.place.dc.get_property_values') + @patch('routes.api.place.fetch_data') + @patch('routes.api.place.stats_api.get_stats_wrapper') + def test_index(self, mock_get_stats, mock_fetch_data, mock_get_place_type): + mock_fetch_data.side_effect = self.side_effect + + mock_get_stats.return_value = json.dumps({ + 'dcid1': { + 'data': { + '2018': 200 + } + }, + 'dcid2': { + 'data': { + '2018': 300 + } + }, + 'dcid3': { + 'data': { + '2018': 100 + } + }, + 'dcid4': { + 'data': { + '2018': 500 + } + }, + }) + + mock_get_place_type.return_value = {'geoId/06': ['State']} + + response = app.test_client().get('/api/place/child/geoId/06') + assert response.status_code == 200 + assert json.loads(response.data) == { + 'County': [{ + 'dcid': 'dcid2', + 'name': 'name2', + 'pop': 300 + }, { + 'dcid': 'dcid1', + 'name': 'name1', + 'pop': 200 + }] + } + + +class TestApiParentPlaces(unittest.TestCase): + + @staticmethod + def side_effect(url, req, compress, post): + if 'geoId/0649670' == req['dcids'][0]: + return { + 'geoId/0649670': { + 'out': [{ + 'dcid': 'geoId/06085', + 'name': 'Santa Clara County', + 'provenanceId': 'dc/sm3m2w3', + 'types': ['AdministrativeArea', 'County'] + }, { + 'dcid': 'geoId/06', + 'name': 'California', + 'provenanceId': 'dc/sm3m2w3', + 'types': ['AdministrativeArea', 'State'] + }] + } + } + elif 'geoId/06' == req['dcids'][0]: + return { + 'geoId/06': { + 'out': [{ + 'dcid': 'country/USA', + 'name': 'United States', + 'provenanceId': 'dc/sm3m2w3', + 'types': ['Country'] + }] + } + } + else: + return {req['dcids'][0]: {}} + + @patch('routes.api.place.fetch_data') + def test_parent_places(self, mock_fetch_data): + mock_fetch_data.side_effect = self.side_effect + response = app.test_client().get('/api/place/parent/geoId/0649670') + assert response.status_code == 200 + assert json.loads(response.data) == [{ + 'dcid': 'geoId/06085', + 'name': 'Santa Clara County', + 'provenanceId': 'dc/sm3m2w3', + 'types': ['County'] + }, { + 'dcid': 'geoId/06', + 'name': 'California', + 'provenanceId': 'dc/sm3m2w3', + 'types': ['State'] + }, { + 'dcid': 'country/USA', + 'name': 'United States', + 'provenanceId': 'dc/sm3m2w3', + 'types': ['Country'] + }] + + +class TestApiPlaceName(unittest.TestCase): + + @patch('routes.api.place.fetch_data') + def test_parent_places(self, mock_fetch_data): + mock_response = { + 'geoId/06': { + 'out': [{ + 'value': 'California', + 'provenance': 'prov1' + }] + }, + 'geoId/07': { + 'out': [] + }, + 'geoId/08': { + 'out': [{ + 'value': 'Colorado', + 'provenance': 'prov2' + }] + } + } + mock_fetch_data.side_effect = ( + lambda url, req, compress, post: mock_response) + + response = app.test_client().get( + '/api/place/name?dcid=geoId/06&dcid=geoId/07&dcid=geoId/08') + assert response.status_code == 200 + assert json.loads(response.data) == { + 'geoId/06': 'California', + 'geoId/07': '', + 'geoId/08': 'Colorado' + } + + +class TestApiDisplayName(unittest.TestCase): + + @patch('routes.api.place.dc.get_property_values') + @patch('routes.api.place.fetch_data') + def test_api_display_name(self, mock_data_fetcher, mock_iso_codes): + dcid1 = 'dcid1' + dcid2 = 'dcid2' + dcid3 = 'dcid3' + us_state_parent = 'parent1' + us_country_parent = 'parent2' + cad_state_parent = 'parent3' + + def side_effect(url, req, compress, post): + if 'containedInPlace' == req['property']: + return { + dcid1: { + 'out': [ + { + 'dcid': us_state_parent, + 'name': us_state_parent, + 'types': ['State'], + }, + { + 'dcid': us_country_parent, + 'name': us_country_parent, + 'types': ['Country'], + }, + ] + }, + dcid2: { + 'out': [{ + 'dcid': us_country_parent, + 'name': us_country_parent, + 'types': ['Country'], + },] + }, + dcid3: { + 'out': [{ + 'dcid': cad_state_parent, + 'name': cad_state_parent, + 'types': ['State'], + },] + }, + cad_state_parent: { + 'out': [] + }, + us_state_parent: { + 'out': [] + }, + us_country_parent: { + 'out': [] + } + } + elif 'name' == req['property']: + return { + dcid1: { + 'out': [{ + 'value': dcid1 + }] + }, + dcid2: { + 'out': [{ + 'value': dcid2 + }] + }, + dcid3: { + 'out': [{ + 'value': dcid3 + }] + }, + } + else: + return {req['dcids'][0]: {}} + + mock_data_fetcher.side_effect = side_effect + mock_iso_codes.return_value = { + us_state_parent: ['US-CA'], + cad_state_parent: ['CA-BC'] + } + response = app.test_client().get( + '/api/place/displayname?dcid=dcid1&dcid=dcid2&dcid=dcid3') + assert response.status_code == 200 + assert json.loads(response.data) == { + dcid1: dcid1 + ', CA', + dcid2: dcid2, + dcid3: dcid3 + } diff --git a/static/js/shared/data_fetcher.test.ts b/static/js/shared/data_fetcher.test.ts index 51bd34f79d..ae3c875fef 100644 --- a/static/js/shared/data_fetcher.test.ts +++ b/static/js/shared/data_fetcher.test.ts @@ -68,6 +68,13 @@ test("fetch stats data", () => { }, }, }); + } else if (url === "/api/place/displayname?&dcid=geoId/05&dcid=geoId/06") { + return Promise.resolve({ + data: { + "geoId/05": "Arkansas", + "geoId/06": "California", + }, + }); } }); @@ -161,6 +168,79 @@ test("fetch stats data", () => { }); }); +test("fetch stats data with state code", () => { + mockedAxios.get.mockImplementation((url: string) => { + if (url === "/api/stats/Count_Person?&dcid=geoId/05&dcid=geoId/06085") { + return Promise.resolve({ + data: { + "geoId/05": { + data: { + "2011": 21000, + "2012": 22000, + }, + placeName: "Arkansas", + provenanceDomain: "source1", + }, + "geoId/06085": { + data: { + "2011": 31000, + "2012": 32000, + }, + placeName: "Santa Clara", + provenanceDomain: "source2", + }, + }, + }); + } else if ( + url === "/api/place/displayname?&dcid=geoId/05&dcid=geoId/06085" + ) { + return Promise.resolve({ + data: { + "geoId/05": "Arkansas", + "geoId/06085": "Santa Clara, CA", + }, + }); + } + }); + + return fetchStatsData(["geoId/05", "geoId/06085"], ["Count_Person"]).then( + (data) => { + expect(data).toEqual({ + data: { + Count_Person: { + "geoId/05": { + data: { + "2011": 21000, + "2012": 22000, + }, + placeName: "Arkansas", + provenanceDomain: "source1", + }, + "geoId/06085": { + data: { + "2011": 31000, + "2012": 32000, + }, + placeName: "Santa Clara, CA", + provenanceDomain: "source2", + }, + }, + }, + dates: ["2011", "2012"], + places: ["geoId/05", "geoId/06085"], + statsVars: ["Count_Person"], + sources: new Set(["source1", "source2"]), + latestCommonDate: "2012", + }); + + expect(data.getPlaceGroupWithStatsVar()).toEqual([ + new DataGroup("Arkansas", [{ label: "Total", value: 22000 }]), + new DataGroup("Santa Clara, CA", [{ label: "Total", value: 32000 }]), + ]); + } + ); +}); + test("fetch stats data where latest date with data for all stat vars is not the latest date", () => { const testData = { "geoId/05": { @@ -185,6 +265,13 @@ test("fetch stats data where latest date with data for all stat vars is not the return Promise.resolve({ data: testData, }); + } else if (url === "/api/place/displayname?&dcid=geoId/05&dcid=geoId/06") { + return Promise.resolve({ + data: { + "geoId/05": "Arkansas", + "geoId/06": "California", + }, + }); } }); @@ -251,6 +338,13 @@ test("fetch stats data where there is no date with data for all stat vars", () = return Promise.resolve({ data: testData, }); + } else if (url === "/api/place/displayname?&dcid=geoId/05&dcid=geoId/06") { + return Promise.resolve({ + data: { + "geoId/05": "Arkansas", + "geoId/06": "California", + }, + }); } }); @@ -435,6 +529,12 @@ test("fetch stats data with per capita with population size 0", () => { }, }, }); + } else if (url === "/api/place/displayname?&dcid=geoId/05") { + return Promise.resolve({ + data: { + "geoId/05": "Arkansas", + }, + }); } }); @@ -531,6 +631,13 @@ test("Per capita with specified denominators test", () => { }, }, }); + } else if (url === "/api/place/displayname?&dcid=geoId/05&dcid=geoId/06") { + return Promise.resolve({ + data: { + "geoId/05": "Arkansas", + "geoId/06": "California", + }, + }); } }); @@ -749,6 +856,15 @@ test("Per capita with specified denominators test - missing place data", () => { "country/USA": null, }, }); + } else if ( + url === "/api/place/displayname?&dcid=geoId/05&dcid=country/USA" + ) { + return Promise.resolve({ + data: { + "geoId/05": "Arkansas", + "country/USA": "USA", + }, + }); } }); diff --git a/static/js/shared/data_fetcher.ts b/static/js/shared/data_fetcher.ts index affe773a27..4b6f4e2e83 100644 --- a/static/js/shared/data_fetcher.ts +++ b/static/js/shared/data_fetcher.ts @@ -35,6 +35,10 @@ interface StatApiResponse { [placeDcid: string]: TimeSeries | null; } +interface DisplayNameApiResponse { + [placeDcid: string]: string; +} + interface CachedStatVarDataMap { [geoId: string]: { [statVar: string]: TimeSeries; @@ -439,11 +443,23 @@ function fetchStatsData( apiDataPromises.push(axios.get(`/api/stats/${denom}${dcidParams}`)); } } + const displayNamesPromise: Promise> = axios.get(`/api/place/displayname${dcidParams}`); - return Promise.all(apiDataPromises).then((allResp) => { + // create list of promises containing apiDataPromises followed by displayNamesPromise + const apiPromises: Promise>[] = []; + apiPromises.push(...apiDataPromises); + apiPromises.push(displayNamesPromise); + + return Promise.all(apiPromises).then((allResp) => { const result = new StatsData(places, statsVars, [], {}, ""); const numOccurencesPerDate: { [key: string]: number } = {}; const numStatVarsPerPlace: { [key: string]: number } = {}; + const displayNameMapping = + allResp.length > 0 && allResp[allResp.length - 1].data + ? allResp[allResp.length - 1].data + : {}; for (let i = 0; i < numStatsVars; i++) { const sv = statsVars[i]; result.data[sv] = allResp[i].data; @@ -466,6 +482,9 @@ function fetchStatsData( numStatVarsPerPlace[place] = 0; } if (!allResp[i].data[place]) continue; + if (displayNameMapping[place]) { + result.data[sv][place].placeName = displayNameMapping[place]; + } const timeSeries = allResp[i].data[place]; if (Object.keys(timeSeries.data).length > 0) { numStatVarsPerPlace[place] = numStatVarsPerPlace[place] + 1; diff --git a/static/js/tools/mock_functions.tsx b/static/js/tools/mock_functions.tsx index f967b63285..98eac1844e 100644 --- a/static/js/tools/mock_functions.tsx +++ b/static/js/tools/mock_functions.tsx @@ -112,6 +112,14 @@ export function axios_mock(): void { }, }, }); + + when(axios.get) + .calledWith("/api/place/displayname?&dcid=geoId/05") + .mockResolvedValue({ + data: { + "geoId/05": "Arkansas", + }, + }); } export function mock_hierarchy_complete(): void {