From 2c0bd25c06ce00a3da7656bc7109bb161e2909d3 Mon Sep 17 00:00:00 2001 From: John Bradley Date: Tue, 17 Oct 2023 14:12:16 -0400 Subject: [PATCH] Fix observations column ordering Updates displayed observations to have the same order as the CSV. Fixes #69 --- andromeda-ui/components/ObservationTable.tsx | 5 +++-- andromeda-ui/pages/fetch-data/index.tsx | 3 +++ andromeda/inaturalist.py | 4 ++-- andromeda/main.py | 1 + andromeda/tests/test_main.py | 12 ++++++++---- 5 files changed, 17 insertions(+), 8 deletions(-) diff --git a/andromeda-ui/components/ObservationTable.tsx b/andromeda-ui/components/ObservationTable.tsx index 7210f7f..45a3020 100644 --- a/andromeda-ui/components/ObservationTable.tsx +++ b/andromeda-ui/components/ObservationTable.tsx @@ -3,6 +3,7 @@ import Image from 'next/image' interface ObservationTableProps { iNatUser: string | undefined; observations: any[]; + observationFieldnames: string[]; totalObservations: number; maxObs: number; } @@ -23,11 +24,11 @@ const KNOWN_COLUMNS = new Set([ ]); export default function ObservationTable(props: ObservationTableProps) { - const { observations, maxObs, iNatUser, totalObservations} = props; + const { observations, observationFieldnames, maxObs, iNatUser, totalObservations} = props; const showing = Math.min(observations.length, maxObs); let extraColumns: string[] = []; if (observations.length > 0) { - extraColumns = Object.keys(observations[0]).filter((x) => !KNOWN_COLUMNS.has(x)) + extraColumns = observationFieldnames.filter((x) => !KNOWN_COLUMNS.has(x)) } const exampleObservations = observations.slice().slice(0, maxObs); const rows = exampleObservations.map((x) => { diff --git a/andromeda-ui/pages/fetch-data/index.tsx b/andromeda-ui/pages/fetch-data/index.tsx index f8a9d4f..5bf11a7 100644 --- a/andromeda-ui/pages/fetch-data/index.tsx +++ b/andromeda-ui/pages/fetch-data/index.tsx @@ -36,6 +36,7 @@ export default function GeneratePage() { const [fetching, setFetching] = useState(false); const [showObservations, setShowObservations] = useState(false); const [observations, setObservations] = useState([]); + const [observationFieldnames, setObservationFieldnames] = useState([]); const [totalObservations, setTotalObservations] = useState(0); const [generateObservationDataset, setGenerateObservationDataset] = useState(false); const [observationsURL, setObservationsURL] = useState(); @@ -58,6 +59,7 @@ export default function GeneratePage() { try { const result = await fetchObservations(iNatUser, addSatRGBData, addLandCover, SHOW_OBS_MAX); setObservations(result.data); + setObservationFieldnames(result.fieldnames); setTotalObservations(result.total); setObservationsURL(undefined); if (result.warnings.length) { @@ -106,6 +108,7 @@ export default function GeneratePage() { {warningNotice} diff --git a/andromeda/inaturalist.py b/andromeda/inaturalist.py index 6fb7e53..8aed9cc 100644 --- a/andromeda/inaturalist.py +++ b/andromeda/inaturalist.py @@ -80,9 +80,9 @@ def get_label(idx, total_observations, reversed): def get_inaturalist_observations(user_id, add_sat_rgb_data, add_landcover_data, limit): idx = 0 missing_lat_long = False - obeservation_ary, total_observations = get_observations(user_id=user_id, limit=limit) + observation_ary, total_observations = get_observations(user_id=user_id, limit=limit) observations = Observations(fieldnames=CSV_FIELDS[:], total=total_observations) - for obs in obeservation_ary: + for obs in observation_ary: observed_on = obs.get("observed_on") if not observed_on: raise BadObservationException(OBSERVED_ON_MISSING_MSG) diff --git a/andromeda/main.py b/andromeda/main.py index c176643..db94284 100644 --- a/andromeda/main.py +++ b/andromeda/main.py @@ -139,6 +139,7 @@ def get_inaturalist(user_id): "user_id": user_id, "total": observations.total, "data": observations.data, + "fieldnames": observations.fieldnames, "warnings": list(observations.warnings) }) elif format == "csv": diff --git a/andromeda/tests/test_main.py b/andromeda/tests/test_main.py index 8cfae00..76eb702 100644 --- a/andromeda/tests/test_main.py +++ b/andromeda/tests/test_main.py @@ -92,8 +92,9 @@ def test_inverse_dimensional_reduction(self, mock_dataset_store): def test_get_inaturalist(self, mock_get_inaturalist_observations): observations = [{"Image_Label": "p1"}] warnings = ["missing_lat_long"] + fieldnames = ["Image_Label"] mock_get_inaturalist_observations.return_value = Mock( - data=observations, warnings=warnings, total=1) + data=observations, fieldnames=fieldnames, warnings=warnings, total=1) client = app.test_client() result = client.get(f"/api/inaturalist/bob") self.assertEqual(result.status_code, 200) @@ -102,6 +103,7 @@ def test_get_inaturalist(self, mock_get_inaturalist_observations): { 'total': 1, "data": [{"Image_Label": "p1"}], + 'fieldnames': ["Image_Label"], "user_id": "bob", "warnings": ["missing_lat_long"], }, @@ -113,9 +115,10 @@ def test_get_inaturalist(self, mock_get_inaturalist_observations): @patch("main.get_inaturalist_observations") def test_get_inaturalist_limit(self, mock_get_inaturalist_observations): observations = [{"Image_Label": "p1"}] + fieldnames = ["Image_Label"] warnings = ["missing_lat_long"] mock_get_inaturalist_observations.return_value = Mock( - data=observations, warnings=warnings, total=1) + data=observations, fieldnames=fieldnames, warnings=warnings, total=1) client = app.test_client() result = client.get(f"/api/inaturalist/bob?limit=6") self.assertEqual(result.status_code, 200) @@ -124,6 +127,7 @@ def test_get_inaturalist_limit(self, mock_get_inaturalist_observations): { 'total': 1, "data": [{"Image_Label": "p1"}], + 'fieldnames': ['Image_Label'], "user_id": "bob", "warnings": ["missing_lat_long"], }, @@ -176,7 +180,7 @@ def test_get_inaturalist_xml(self, mock_get_inaturalist_observations): @patch("main.get_inaturalist_observations") def test_get_inaturalist_add_rgb(self, mock_get_inaturalist_observations): - mock_get_inaturalist_observations.return_value = Mock(data=[], warnings=[], total=0) + mock_get_inaturalist_observations.return_value = Mock(data=[], fieldnames=[], warnings=[], total=0) client = app.test_client() result = client.get(f"/api/inaturalist/bob?format=json&add_sat_rgb_data=true") self.assertEqual(result.status_code, 200) @@ -185,7 +189,7 @@ def test_get_inaturalist_add_rgb(self, mock_get_inaturalist_observations): @patch("main.get_inaturalist_observations") def test_get_inaturalist_add_landcover(self, mock_get_inaturalist_observations): - mock_get_inaturalist_observations.return_value = Mock(data=[], warnings=[], total=0) + mock_get_inaturalist_observations.return_value = Mock(data=[], fieldnames=[], warnings=[], total=0) client = app.test_client() result = client.get(f"/api/inaturalist/bob?format=json&add_landcover_data=true") self.assertEqual(result.status_code, 200)