Skip to content

Commit

Permalink
Merge pull request #1 from PnX-SI/feat/promise
Browse files Browse the repository at this point in the history
Feat(API): Add functions to retrieve occurrences from diff sources (GBIF, GN)
  • Loading branch information
CynthiaBorotPNV authored Nov 7, 2024
2 parents c51bfbe + 0842984 commit c7783b3
Show file tree
Hide file tree
Showing 7 changed files with 365 additions and 127 deletions.
50 changes: 14 additions & 36 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,53 +19,31 @@ <h1 id="taxonName"></h1>
<div class="card-header">Liste de status</div>
<ul id="listeStatuts" class="list-group list-group-flush"></ul>
</div>
<div class="card" style="width: 18rem">
<div class="card-header">Liste de status</div>
<ul id="taxonList" class="list-group list-group-flush"></ul>
</div>
</div>
</body>
<script
src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"
integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4"
crossorigin="anonymous"
></script>
<script src="https://cdn.jsdelivr.net/npm/@turf/turf@7/turf.min.js"></script>
<script src="js/status.js"></script>
<script src="js/utils.js"></script>
<script src="js/media.js"></script>
<script src="js/taxon.js"></script>
<script src="js/config.js"></script>
<script>
const taxonData = {
"Capra Ibex": {
name: "Capra Ibex",
cd_ref: 61098,
gbifId: 2441055,
count: 125,
},
};

getTaxRefCdNom(taxonData["Capra Ibex"].gbifId).then(function (res) {
console.log(res);
});
const listeStatusUl = document.getElementById("listeStatuts");
document.getElementById("taxonName").innerHTML =
taxonData["Capra Ibex"].name;

getStatusForATaxon(taxonData["Capra Ibex"]).then(function (res) {
res.status.forEach((element) => {
const statusTypeAvailable = Object.keys(labels);
statusTypeAvailable.forEach(function (statusType) {
// if no data available for this status Type
if (!element[statusType]) {
return;
}
var li = document.createElement("li");
li.classList.add("list-group-item");
li.innerHTML = `<span class="badge bg-primary rounded-pill">${labels[statusType]}</span><span>${element[statusType]}</span>`;

listeStatusUl.appendChild(li);
});
wkt =
"POLYGON ((3.6067457860489474 44.31735648705861, 3.6067235753826665 44.31753222361296, 3.606654037712057 44.31770147249114, 3.606539844959545 44.31785772946521, 3.606385385237379 44.31799498953319, 3.6061965942531686 44.318107977708294, 3.60598072721813 44.31819235175796, 3.605746080021263 44.3182448690979, 3.605501670386475 44.31826351142357, 3.6052568912711283 44.3182475622866, 3.605021149834159 44.31819763463273, 3.6048035058580408 44.31811564724215, 3.6046123235298966 44.318004750978425, 3.604454949972245 44.31786920768214, 3.6043374328830575 44.31771422636648, 3.6042642881382485 44.317545763013385, 3.6042383262856137 44.317370291667636, 3.6042605445924387 44.31719455562893, 3.604330088786867 44.317025308305304, 3.6044442859532793 44.31686905368802, 3.6045987473074517 44.31673179642029, 3.604787536893315 44.31661881106261, 3.60500339971254 44.31653443941854, 3.605238040517946 44.3164819237062, 3.6054824425586673 44.31646328198232, 3.6057272140334704 44.316479230603655, 3.605962948946621 44.316529156702984, 3.606180588508839 44.31661114173676, 3.606371769204977 44.31672203520022, 3.6065291441609757 44.316857575679116, 3.6066466654659757 44.31701255458916, 3.6067198166022463 44.31718101631465, 3.6067457860489474 44.31735648705861))";
// Get Taxon list
getAllTopNTaxon(wkt, config.NB_MAX_TAXONS).then((listTaxons) => {
completeTaxonsData(listTaxons).then((listTaxonsModified) => {
console.log(listTaxonsModified);
});
});

wkt =
"POLYGON ((3.6067457860489474 44.31735648705861, 3.6067235753826665 44.31753222361296, 3.606654037712057 44.31770147249114, 3.606539844959545 44.31785772946521, 3.606385385237379 44.31799498953319, 3.6061965942531686 44.318107977708294, 3.60598072721813 44.31819235175796, 3.605746080021263 44.3182448690979, 3.605501670386475 44.31826351142357, 3.6052568912711283 44.3182475622866, 3.605021149834159 44.31819763463273, 3.6048035058580408 44.31811564724215, 3.6046123235298966 44.318004750978425, 3.604454949972245 44.31786920768214, 3.6043374328830575 44.31771422636648, 3.6042642881382485 44.317545763013385, 3.6042383262856137 44.317370291667636, 3.6042605445924387 44.31719455562893, 3.604330088786867 44.317025308305304, 3.6044442859532793 44.31686905368802, 3.6045987473074517 44.31673179642029, 3.604787536893315 44.31661881106261, 3.60500339971254 44.31653443941854, 3.605238040517946 44.3164819237062, 3.6054824425586673 44.31646328198232, 3.6057272140334704 44.316479230603655, 3.605962948946621 44.316529156702984, 3.606180588508839 44.31661114173676, 3.606371769204977 44.31672203520022, 3.6065291441609757 44.316857575679116, 3.6066466654659757 44.31701255458916, 3.6067198166022463 44.31718101631465, 3.6067457860489474 44.31735648705861))";

speciesList = {};
getGbifTaxon(wkt, speciesList, 0);
</script>
</html>
26 changes: 26 additions & 0 deletions js/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const config = {
NB_MAX_TAXONS: 10,
STATUS_LABELS: {
worldRedList: "Liste Rouge Mondiale",
europeanRedList: "Liste Rouge europeenne",
nationalRedList: "Liste Rouge nationale",
localRedList: "Liste Rouge locale",
bonnConvention: "Convention de Bonn",
bernConvention: "Convention de Bern",
barcelonaConvention: "Convention de Barcelona",
osparConvention: "Convention d'Ospar",
hffDirective: "Directive Habitats Faune Flore",
birdDirective: "Directive Oiseau",
nationalProtection: "Protection nationale",
regionalProtection: "Protection regionale",
departementalProtection: "Protection départementale",
nationalActionPlan: "Plan d'Action Nationale",
scapNationale: "Stratégie nationale pour les aires protégées",
scapRegionale: "Stratégie régionale pour les aires protégées",
sensibilite: "Sensibilité",
biogeoStatus: "Status biogeo",
reglementation: "Réglementation",
invasiveReglementation: "Réglementation invasive",
prioriteActionPubliqueNationale: "Priorité d'action publique nationale",
},
};
36 changes: 18 additions & 18 deletions js/media.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
async function addMedia2Json(speciesDict) {
console.log("addMedia2Json");
for(key in speciesDict) {
url = 'https://api.gbif.org/v1/species/' + speciesDict[key].gbifId + '/media';
/**
* Fetch the url of the first image for a given GBIF id.
* @param {number} gbifId - GBIF id of the taxon
* @returns {Promise<string>} - a promise resolving to the url of the first
* image for the given taxon, or undefined if no image is found
*/
function getMedias(gbifId) {
url = "https://api.gbif.org/v1/species/" + gbifId + "/media";

await fetch(url,{method:'GET'})
.then(function(response) {return response.json(); })
.then(function(json) {
// Media checking
if (json.results.length > 0) {
speciesDict[key].media = json.results[0].identifier;
console.log(speciesDict[key].media + "<br>");
}
});
console.log(key + "<br>");
console.log(url + "<br>");
}

return speciesDict;
return fetch(url, { method: "GET" })
.then(function (response) {
return response.json();
})
.then(function (json) {
// Media checking
if (json.results.length > 0) {
return json.results[0].identifier;
}
});
}
40 changes: 15 additions & 25 deletions js/status.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,16 @@
const labels ={worldRedList: "Liste Rouge Mondiale",
europeanRedList: "Liste Rouge europeenne",
nationalRedList: "Liste Rouge nationale",
localRedList: "Liste Rouge locale",
bonnConvention: "Convention de Bonn",
bernConvention: "Convention de Bern",
barcelonaConvention: "Convention de Barcelona",
osparConvention: "Convention d'Ospar",
hffDirective: "Directive Habitats Faune Flore",
birdDirective: "Directive Oiseau",
nationalProtection: "Protection nationale",
regionalProtection: "Protection regionale",
departementalProtection: "Protection départementale",
nationalActionPlan: "Plan d'Action Nationale",
scapNationale: "Stratégie nationale pour les aires protégées",
scapRegionale: "Stratégie régionale pour les aires protégées",
sensibilite: "Sensibilité",
biogeoStatus: "Status biogeo",
reglementation: "Réglementation",
invasiveReglementation: "Réglementation invasive",
prioriteActionPubliqueNationale: "Priorité d'action publique nationale",}
async function getStatusForATaxon(taxonData) {
const reponse = await fetch(`https://taxref.mnhn.fr/api/taxa/${taxonData.cd_ref}/status/columns`);
const status = await reponse.json();
return status._embedded
/**
* Given a taxonData object, fetch its status data from TaxRef API
* @param {Object} taxonData - a taxon data object with a cd_ref property
* @returns {Promise<Object[]>} - a list of status objects
*/
function getStatusForATaxon(taxonData) {
return fetch(
`https://taxref.mnhn.fr/api/taxa/${taxonData.cd_ref}/status/columns`
)
.then((response) => {
return response.json();
})
.then((json) => {
return json._embedded?.status;
});
}
166 changes: 140 additions & 26 deletions js/taxon.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,143 @@
function getGbifTaxon(wkt, speciesList, page) {
console.log("getGbifTaxon", page);
const limit = 300;
const offset = page * limit;
geometry = wkt;
fetch(
"https://api.gbif.org/v1/occurrence/search?geometry=${geometry}&limit=${limit}&offset=${offset}"
)
.then(function (response) {
return response.json();
})
.then(function (data) {
data.results.forEach((element) => {
occCount = (speciesList[element.species] || {})["occCount"] || 0;
speciesList[element.species] = {
gbifId: element.taxonKey,
occCount: occCount + 1,
};
});
const DEFAULT_NB_MAX_TAXONS = 10;

console.log(speciesList);
if (data.endOfRecords == false) {
getGbifTaxon(wkt, speciesList, page + 1);
}
})
.catch(function (err) {
console.log(err);
/**
* Fetch a page of taxon data from GBIF given a WKT string
* @param {string} wkt - Well-Known Text representation of a polygon
* @param {number} limit - number of results to return
* @param {number} offset - offset of the first result
* @returns {Promise<import('gbif-types').GBIFSearchResponse>}
*/
function fetchApiTaxonGbif(wkt, limit, offset) {
return fetch(
`https://api.gbif.org/v1/occurrence/search?geometry=${wkt}&limit=${limit}&offset=${offset}`
).then((response) => {
return response.json();
});
}

/**
* Fetch the list of taxons from GBIF given a WKT string
* @param {string} wkt - Well-Known Text representation of a polygon
* @param {number} [nbMaxTaxons=DEFAULT_NB_MAX_TAXONS] - maximum number of results to return
* @param {Object} [params={ limit: 300 }] - parameters to pass to the API
* @returns {Promise<Array<{gbifId: number, occCount: number, species: string}>>} - a list of taxons with their occurrence count and GBIF id
*/
function getGbifTaxon(
wkt,
nbMaxTaxons = DEFAULT_NB_MAX_TAXONS,
params = { limit: 300 }
) {
return (
fetch(`https://api.gbif.org/v1/occurrence/search?geometry=${wkt}&limit=1`)
.then((response) => {
return response.json();
})
// Get total number of occurrences
.then((data) => {
return data.count;
})
.then(async function (countOccurrence) {
// Compute the number of pages we need to query
const nbOfPages = Math.ceil(countOccurrence / params.limit);

// Create a promise for each page
let promises = [];
for (let pageIndex = 0; pageIndex < nbOfPages; pageIndex++) {
const offset = pageIndex * params.limit;
promises.push(fetchApiTaxonGbif(wkt, params.limit, offset));
}
let speciesList = {};
// Run all promises and await for the responses
await Promise.all(promises).then((listOfData) => {
listOfData
.map((apiResult) => {
return apiResult.results;
})
// For each page
.forEach((resultsPage) => {
// For each occurrence retrieve the gbifID and increase occurrence count
resultsPage.forEach((taxonData) => {
occCount =
(speciesList[taxonData.species] || {})["occCount"] || 0;
speciesList[taxonData.species] = {
gbifId: taxonData.taxonKey,
occCount: occCount + 1,
};
});
});
});
return speciesList;
})
.then((taxonsData) => {
let data = [];
Object.keys(taxonsData).forEach((value) => {
data.push([value, taxonsData[value]["occCount"]]);
});
data.sort(function (a, b) {
return b[1] - a[1];
});
data = data.slice(0, nbMaxTaxons).map((x) => {
return x[0];
});
let newTaxonsData = [];
data.forEach((key) => {
newTaxonsData.push({ ...taxonsData[key], species: key });
});
return newTaxonsData;
})
);
}

/**
* Fetch a list of taxon data from the GTSI API given a WKT string
* @param {string} wkt - Well-Known Text representation of a polygon
* @param {number} [nbMaxTaxons=DEFAULT_NB_MAX_TAXONS] - number of results to return
* @returns {Promise<import('gbif-types').GBIFTaxon[]>}
*/
function getPgRestTaxon(wkt, nbMaxTaxons = DEFAULT_NB_MAX_TAXONS) {
const geometry = wkt;
return (
fetch(
`https://dev-gtsi.cevennes-parcnational.net/api/rpc/get_taxa_list?in_wkt=${geometry}&in_limit=${nbMaxTaxons}`
)
.then((response) => {
return response.json();
})
// Get total number of occurrences
.then((data) => {
return data.map(
({
count_occ: occCount,
species_name: species,
species_key: gbifId,
...rest
}) => ({
occCount,
species,
gbifId,
...rest,
})
);
})
);
}

/**
* Get the top N taxons from both the GTSI API and the GBIF API given a WKT string
* @param {string} wkt - Well-Known Text representation of a polygon
* @param {number} [nbMaxTaxons=DEFAULT_NB_MAX_TAXONS] - number of results to return
* @returns {Promise<import('gbif-types').GBIFTaxon[]>} - a list of taxons with their occurrence count and GBIF id
*/
function getAllTopNTaxon(wkt, nbMaxTaxons = DEFAULT_NB_MAX_TAXONS) {
let promises = [
getPgRestTaxon(wkt, nbMaxTaxons),
getGbifTaxon(wkt, nbMaxTaxons),
];
return Promise.all(promises).then((listOfData) => {
const allData = [...listOfData[0], ...listOfData[1]];
allData.sort(function (a, b) {
return b["occCount"] - a["occCount"];
});
return Promise.resolve(allData.slice(0, nbMaxTaxons));
});
}
Loading

0 comments on commit c7783b3

Please sign in to comment.