Skip to content

Commit f793974

Browse files
authored
Update csv output for fada taxa list (#5023)
1 parent 7b76772 commit f793974

File tree

3 files changed

+183
-32
lines changed

3 files changed

+183
-32
lines changed

bims/fada/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# FADA-specific functionality

bims/fada/taxa_list.py

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
# coding=utf-8
2+
"""
3+
FADA-specific taxa list export configuration and utilities.
4+
"""
5+
from bims.scripts.species_keys import BIOGRAPHIC_DISTRIBUTIONS
6+
7+
# FADA-only additional_data keys (column names)
8+
FADA_ADDITIONAL_KEYS = [
9+
'Taxonomic Comments',
10+
'Taxonomic References',
11+
'Biogeographic Comments',
12+
'Biogeographic References',
13+
'Environmental Comments',
14+
'Environmental References',
15+
'Conservation Comments',
16+
'Conservation References',
17+
]
18+
19+
# Columns to exclude for FADA exports
20+
FADA_EXCLUDED_COLUMNS = [
21+
'variety', 'Variety',
22+
'origin', 'Origin',
23+
'endemism', 'Endemism',
24+
'invasion', 'Invasion',
25+
'conservation_status_global', 'Conservation status global',
26+
'conservation_status_national', 'Conservation status national',
27+
'gbif_coordinate_uncertainty_m', 'Gbif coordinate uncertainty m',
28+
'gbif_coordinate_precision', 'Gbif coordinate precision',
29+
'cites_listing', 'Cites listing', 'CITES listing',
30+
# Scientific name and authority is excluded for FADA (author is separate)
31+
'scientific_name_and_authority', 'Scientific name and authority',
32+
]
33+
34+
# Biogeographic distributions in alphabetical order
35+
FADA_BIOGRAPHIC_ORDER = sorted(BIOGRAPHIC_DISTRIBUTIONS)
36+
37+
38+
def get_environmental_tags_order():
39+
"""
40+
Get the ordered list of environmental tag names from TagGroup.
41+
Tags are ordered by their TagGroup's order, then by the tag name within each group.
42+
"""
43+
from bims.models import TagGroup
44+
45+
ordered_tags = []
46+
for tag_group in TagGroup.objects.prefetch_related('tags').order_by('order'):
47+
for tag in tag_group.tags.all().order_by('name'):
48+
if tag.name not in ordered_tags:
49+
ordered_tags.append(tag.name)
50+
return ordered_tags
51+
52+
53+
def reorder_headers_for_fada(headers):
54+
"""
55+
Reorder headers for FADA export
56+
"""
57+
headers = [h for h in headers if h not in FADA_EXCLUDED_COLUMNS]
58+
59+
# Get environmental tags order from TagGroup
60+
environmental_tags_order = get_environmental_tags_order()
61+
62+
biogeographic_comments = ['Biogeographic References', 'Biogeographic Comments']
63+
environmental_comments = ['Environmental References', 'Environmental Comments']
64+
# Taxonomic Reference before Taxonomic Comments
65+
taxonomic_comments = ['Taxonomic References', 'Taxonomic Comments']
66+
conservation_comments = ['Conservation Comments', 'Conservation References']
67+
68+
base_headers = []
69+
biographic_headers = []
70+
environmental_headers = []
71+
72+
for h in headers:
73+
if h in FADA_BIOGRAPHIC_ORDER:
74+
biographic_headers.append(h)
75+
elif h in environmental_tags_order:
76+
environmental_headers.append(h)
77+
elif h in FADA_ADDITIONAL_KEYS:
78+
continue
79+
else:
80+
base_headers.append(h)
81+
82+
if 'fada_id' in base_headers and 'taxon_rank' in base_headers:
83+
taxon_rank_idx = base_headers.index('taxon_rank')
84+
base_headers.remove('fada_id')
85+
base_headers.insert(taxon_rank_idx, 'fada_id')
86+
87+
if 'species_group' in base_headers and 'species' in base_headers:
88+
species_idx = base_headers.index('species')
89+
base_headers.remove('species_group')
90+
base_headers.insert(species_idx, 'species_group')
91+
92+
if 'author' in base_headers and 'taxon' in base_headers:
93+
taxon_idx = base_headers.index('taxon')
94+
base_headers.remove('author')
95+
base_headers.insert(taxon_idx + 1, 'author')
96+
97+
if 'accepted_taxon' in base_headers and 'taxonomic_status' in base_headers:
98+
taxonomic_status_idx = base_headers.index('taxonomic_status')
99+
base_headers.remove('accepted_taxon')
100+
base_headers.insert(taxonomic_status_idx + 1, 'accepted_taxon')
101+
102+
biographic_headers = sorted(biographic_headers)
103+
104+
# Sort environmental headers according to TagGroup order
105+
env_order_map = {tag: idx for idx, tag in enumerate(environmental_tags_order)}
106+
environmental_headers = sorted(
107+
environmental_headers,
108+
key=lambda x: env_order_map.get(x, len(environmental_tags_order))
109+
)
110+
111+
result = []
112+
113+
for h in base_headers:
114+
result.append(h)
115+
if h == 'accepted_taxon':
116+
for tc in taxonomic_comments:
117+
if tc in headers:
118+
result.append(tc)
119+
if h == 'gbif_link':
120+
result.extend(biographic_headers)
121+
for bc in biogeographic_comments:
122+
if bc in headers:
123+
result.append(bc)
124+
125+
if 'fada_id' not in base_headers:
126+
result.extend(biographic_headers)
127+
for bc in biogeographic_comments:
128+
if bc in headers:
129+
result.append(bc)
130+
result.extend(environmental_headers)
131+
for ec in environmental_comments:
132+
if ec in headers:
133+
result.append(ec)
134+
135+
for cc in conservation_comments:
136+
if cc in headers:
137+
result.append(cc)
138+
139+
return result

bims/tasks/download_taxa_list.py

Lines changed: 43 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,15 @@
1313
from reportlab.platypus import Paragraph, Spacer, SimpleDocTemplate
1414
from reportlab.pdfbase import pdfmetrics
1515
from reportlab.pdfbase.ttfonts import TTFont
16+
from reportlab.pdfbase.pdfmetrics import registerFontFamily
1617

1718
from bims.scripts.species_keys import (
1819
ACCEPTED_TAXON, TAXON_RANK,
1920
COMMON_NAME, CLASS, SUBSPECIES,
20-
CITES_LISTING, FADA_ID, ON_GBIF, GBIF_LINK
21+
CITES_LISTING, FADA_ID, ON_GBIF, GBIF_LINK,
22+
SPECIES_GROUP, SUBGENUS, SUBTRIBE, SUBFAMILY,
23+
SUBORDER, SUBCLASS, SUBPHYLUM, SPECIES, GENUS,
24+
TRIBE, FAMILY, ORDER, PHYLUM, KINGDOM, AUTHORS
2125
)
2226
from bims.utils.domain import get_current_domain
2327

@@ -41,22 +45,14 @@ def process_download_csv_taxa_list(request, csv_file_path, filename, user_id, do
4145
from bims.models.taxon_group import TaxonGroup
4246
from bims.models import TaxonGroupCitation
4347
from bims.templatetags import is_fada_site
48+
from bims.fada.taxa_list import (
49+
FADA_ADDITIONAL_KEYS,
50+
reorder_headers_for_fada,
51+
)
4452

4553
is_fada = is_fada_site()
4654
sanparks_project = is_sanparks_project()
4755

48-
# FADA-only additional_data keys (column names)
49-
FADA_ADDITIONAL_KEYS = [
50-
'Taxonomic Comments',
51-
'Taxonomic References',
52-
'Biogeographic Comments',
53-
'Biogeographic References',
54-
'Environmental Comments',
55-
'Environmental References',
56-
'Conservation Comments',
57-
'Conservation References',
58-
]
59-
6056
def _from_additional_data(instance, k):
6157
data = getattr(instance, 'additional_data', None)
6258
if not data:
@@ -120,25 +116,45 @@ def __init__(self, get_data, user=None):
120116
additional_attributes_titles = set()
121117

122118
def update_headers(_headers):
119+
header_map = {
120+
'class_name': CLASS,
121+
'taxon_rank': TAXON_RANK,
122+
'common_name': COMMON_NAME,
123+
'accepted_taxon': ACCEPTED_TAXON,
124+
'fada_id': FADA_ID,
125+
'species_group': SPECIES_GROUP,
126+
'subgenus': SUBGENUS,
127+
'subtribe': SUBTRIBE,
128+
'subfamily': SUBFAMILY,
129+
'suborder': SUBORDER,
130+
'subclass': SUBCLASS,
131+
'subphylum': SUBPHYLUM,
132+
'subspecies': SUBSPECIES,
133+
'species': SPECIES,
134+
'genus': GENUS,
135+
'tribe': TRIBE,
136+
'family': FAMILY,
137+
'order': ORDER,
138+
'phylum': PHYLUM,
139+
'kingdom': KINGDOM,
140+
'cites_listing': CITES_LISTING,
141+
'author': AUTHORS,
142+
'taxonomic_status': 'Taxonomic Status',
143+
}
144+
123145
_updated_headers = []
124146
for header in _headers:
125147
if header in FADA_ADDITIONAL_KEYS:
126148
_updated_headers.append(header)
127149
continue
128150
original = header
129-
if header == 'class_name':
130-
header = CLASS
131-
elif header == 'taxon_rank':
132-
header = TAXON_RANK
133-
elif header == 'common_name':
134-
header = COMMON_NAME
135-
elif header == 'accepted_taxon':
136-
header = ACCEPTED_TAXON
137-
elif header == 'fada_id':
138-
header = FADA_ID
151+
152+
if header.lower() in header_map:
153+
header = header_map[header.lower()]
139154
_updated_headers.append(header)
140155
continue
141-
elif header.lower().strip() in ['on_gbif', 'on gbif']:
156+
157+
if header.lower().strip() in ['on_gbif', 'on gbif']:
142158
header = ON_GBIF
143159
_updated_headers.append(header)
144160
continue
@@ -159,10 +175,6 @@ def update_headers(_headers):
159175
and original not in additional_attributes_titles
160176
):
161177
header = header.replace('_', ' ').capitalize()
162-
if header == 'Subspecies':
163-
header = SUBSPECIES
164-
if header.lower().strip() == 'cites_listing':
165-
header = CITES_LISTING
166178

167179
_updated_headers.append(header)
168180
return _updated_headers
@@ -189,6 +201,7 @@ def update_headers(_headers):
189201
for k in FADA_ADDITIONAL_KEYS:
190202
if k not in raw_headers:
191203
raw_headers.append(k)
204+
raw_headers = reorder_headers_for_fada(raw_headers)
192205

193206
updated_headers = update_headers(raw_headers)
194207

@@ -296,8 +309,6 @@ def get_checklist_paragraphs(taxon_group, taxonomies):
296309
pdfmetrics.registerFont(TTFont('Garamond-Italic', os.path.join(font_dir, 'EBGaramond-Italic.ttf')))
297310
pdfmetrics.registerFont(TTFont('Garamond-BoldItalic', os.path.join(font_dir, 'EBGaramond-BoldItalic.ttf')))
298311

299-
# Register font family so <i> and <b> tags work in Paragraphs
300-
from reportlab.pdfbase.pdfmetrics import registerFontFamily
301312
registerFontFamily(
302313
'Garamond',
303314
normal='Garamond',
@@ -401,15 +412,15 @@ def get_checklist_paragraphs(taxon_group, taxonomies):
401412
genus_line = g_obj.canonical_name
402413
genus_author = ''
403414
if g_obj.author and g_obj.author not in genus_line:
404-
genus_author += f", {g_obj.author}"
415+
genus_author += f" {g_obj.author}"
405416

406417
paragraphs.append(Paragraph(f"<i>{genus_line}</i>{genus_author}", genus_style))
407418
paragraphs.append(Spacer(1, 10))
408419

409420
for s_obj in info['species']:
410421
sp_line = f'<i>{s_obj.canonical_name}</i>'
411422
if s_obj.author:
412-
sp_line += f", {s_obj.author}"
423+
sp_line += f" {s_obj.author}"
413424
if s_obj.origin:
414425
sp_line += f" : {s_obj.origin.upper()}"
415426
if "type species" in (s_obj.additional_data or {}):

0 commit comments

Comments
 (0)