Most compound forms (hybrids and species pairs) will not be affected if the user selects subspecies lumping. However, there are a few cases that are. For example, Dr. John Trochet, compiler of the Zuñi CBC, often reports hybrids of different forms of Dark-eyed Junco. Also, a record reported as “Audubon or Myrtle Warbler” should be report as Yellow-rumped Warbler if the user has requested subspecies lumping.
# - - - l u m p C o m p o u n d F o r m
def lumpCompoundForm(c, txny):
'''Subspecies lumping: compound form case
[ (c is a pycbc.Census instance with a compound form) and
(txny is a taxonomy as an xnomo3.Txny instance) ->
if c.form and c.alt_form are defined in txny ->
if c.form and c.alt_form are subspecies of
the same species ->
return the code for that species
else -> return None
else -> raise ScriptError ]
'''
In order to check the ranks of the affected taxa, we retrieve the depth codes for subspecies and species ranks.
#-- 1
# [ subspDepth := depth of subspecies rank in txny
# spDepth := depth of species rank in txny ]
subspDepth = txny.hier.formRank().depth
spDepth = txny.hier.speciesRank().depth
The first step is to retrieve the Taxon
instances for both the component form codes, assuming that
they are known to the taxonomic database.
#-- 2
# [ if c.form and c.alt_form are defined in txny ->
# taxon1 := the txny.Taxon instance for c.form
# taxon2 := the txny.Taxon instance for c.alt_form
# else -> raise ScriptError ]
try:
taxon1 = txny.lookupAbbr(c.form)
except KeyError:
raise lib.ScriptError("Unknown bird code in %s-%s: '%s'" %
(c.year_no, c.year_key, c.form))
try:
taxon2 = txny.lookupAbbr(c.alt_form)
except KeyError:
raise lib.ScriptError("Unknown bird code in %s-%s: '%s'" %
(c.year_no, c.year_key, c.alt_form))
If either of these taxa are not subspecies, return None to signify that there is no change.
#-- 3
# [ if taxon1 and taxon2 are both subspecies ->
# I
# else -> return None ]
if ((taxon1.rank.depth != subspDepth) or
(taxon2.rank.depth != subspDepth)):
return None
At this point we know that both form codes are subspecies, but
they might be subspecies of different species. Fortunately,
the xnomo3 module's Taxon class
has a handy method that computes the deepest common ancestor
of two taxa; if this ancestor is at species level, we can
conclude that taxon1 and taxon2
are subspecies of that same species.
#-- 4
# [ if the nearest common ancestor of taxon1 and taxon2 has
# species rank ->
# return the code for that ancestor
# else -> return None ]
commonAncestor = taxon1.nearestAncestor(taxon2)
if commonAncestor.rank.depth == spDepth:
return commonAncestor.abbr
else:
return None