UNPKG

globi-data

Version:

Find out who eats who in the world: what do rats (Rattus rattus) eat?, or what do hardhead catfish (Ariopsis felis) eat?. Data provided via Global Biotic Interactions (GloBI, https://globalbioticinteractions.org) .

440 lines (392 loc) 14.9 kB
var nodeXHR = require('xmlhttprequest'); var extend = require('extend'); var hash = require('object-hash'); var querystring = require('querystring'); var citation = require('./citation.js'); var request = require('request'); var globiData = {}; var urlPrefix = 'https://api.globalbioticinteractions.org'; globiData.addQueryParams = function (uri, search) { function initParams(search) { var alt = extend({}, search); if (search.location) { alt = extend(alt, search.location); delete alt.location; } function replaceAndDelete(match, replace) { if (search[match]) { if (!alt[replace]) { alt[replace] = search[match]; } delete alt[match]; } } replaceAndDelete('sourceTaxa', 'sourceTaxon'); replaceAndDelete('targetTaxa', 'targetTaxon'); replaceAndDelete('fields', 'field'); if (search.includeObservations) { alt.includeObservations = true; } if (search.exactNameMatchOnly) { alt.exactNameMatchOnly = true; } if (search.excludeChildTaxa) { alt.excludeChildTaxa = true; } return alt; } var qs = querystring.encode(initParams(search)); var altUri = uri; if (qs.length > 0) { altUri = uri + '&' + qs; } return altUri; } ; globiData.urlForFindCloseTaxonMatches = function (name) { return urlPrefix + '/findCloseMatchesForTaxon/' + encodeURIComponent(name); }; globiData.urlForTaxonInteractionQuery = function (search) { var uri = urlPrefix; var searchAlt = extend({}, search); if (searchAlt.sourceTaxonScientificName) { uri = uri + '/taxon/' + encodeURIComponent(searchAlt.sourceTaxonScientificName); delete searchAlt.sourceTaxonScientificName; if (searchAlt.interactionType) { uri = uri + '/' + encodeURIComponent(searchAlt.interactionType); delete searchAlt.interactionType; } if (searchAlt.targetTaxonScientificName) { uri = uri + '/' + encodeURIComponent(searchAlt.targetTaxonScientificName); delete searchAlt.targetTaxonScientificName; } } else { uri = uri + '/interaction'; } var ext = {'csv': '.csv', 'dot': '.dot'} uri = uri + (ext[searchAlt.resultType] === undefined ? '' : ext[searchAlt.resultType]); uri = uri + '?type=' + (searchAlt.resultType ? searchAlt.resultType : 'json.v2'); delete searchAlt.resultType; return this.addQueryParams(uri, searchAlt); }; globiData.urlForTaxonImageQuery = function (scientificName, opts) { var suffix = ''; if (opts && opts.lang) { suffix = '&lang=' + encodeURIComponent(opts.lang); } return urlPrefix + '/imagesForName?name=' + encodeURIComponent(scientificName) + suffix; }; globiData.urlForTaxonImageByIdQuery = function (id) { return urlPrefix + '/images/' + encodeURIComponent(id); }; globiData.urlForTaxonImagesQuery = function (scientificNames) { var nameQuery = '?'; if (scientificNames) { for (var index in scientificNames) { if (scientificNames.hasOwnProperty(index)) { nameQuery += 'name=' + encodeURIComponent(scientificNames[index]) + '&'; } } } return urlPrefix + '/imagesForNames' + nameQuery; }; globiData.urlForStudyStats = function (search) { var url = urlPrefix + '/reports/studies'; if (search.source) { url = url + '?source=' + encodeURIComponent(search.source); } return url; }; var createReq = function () { var req; if (typeof window === 'undefined') { // perhaps running in node.js? req = new nodeXHR.XMLHttpRequest(); } else if (window.XMLHttpRequest) { // Mozilla, Safari, ... req = new XMLHttpRequest(); } else if ((typeof window !== 'undefined') && window.ActiveXObject) { // IE try { req = new ActiveXObject('Msxml2.XMLHTTP'); } catch (e) { try { req = new ActiveXObject('Microsoft.XMLHTTP'); } catch (e) { } } } return req; }; globiData.findSources = function (callback) { var req = createReq(); req.open('GET', urlPrefix + '/reports/sources', true); req.onreadystatechange = function () { if (req.readyState === 4 && req.status === 200) { var result = JSON.parse(req.responseText); callback(citation.extractCitations(result)); } }; req.send(null); }; globiData.findSourceNames = function (callback) { function lookupSources(path, callback) { request({ method: 'GET', uri: urlPrefix + path, withCredentials: false, gzip: true }, function (error, response, body) { if (!error && response.statusCode == 200) { var sources = JSON.parse(body); var sourceNames = sources.map(function (source) { if (source.study_source_id !== undefined) { source.name = source.study_source_id.replace('globi:', ''); } if (source.study_source_doi !== undefined) { source.doi = source.study_source_doi; } return source; }); callback(sourceNames); } }); } lookupSources('/source/?type=json.v2', function(sourceNames) { lookupSources('/dataset/?type=json.v2', function(sourcesAll) { var sourceNamespacesWithReport = sourceNames.map(function(source) { return source.name; }); var sourcesNoReport = sourcesAll .filter(function(source) { return sourceNamespacesWithReport.indexOf(source.name) === -1; }) callback(sourceNames.concat(sourcesNoReport)); }); }); }; globiData.findStudyStats = function (search, callback) { var req = createReq(); var uri = globiData.urlForStudyStats(search); req.open('GET', uri, true); req.onreadystatechange = function () { if (req.readyState === 4 && req.status === 200) { var resp = JSON.parse(req.responseText); var studyStats = []; for (var i = 0; i < resp.data.length; i++) { var row = resp.data[i]; var stats = { citation: row[0], source: row[3], totalInteractions: row[4], totalTaxa: row[5]}; var doi = row[2]; if (doi && doi.length > 0) { stats.doi = doi; } var externalId = row[1]; if (externalId && externalId.length > 0 && externalId.match('^((http)|(https))://') !== null) { stats.url = externalId; } studyStats[i] = stats; } callback(studyStats); } }; req.send(null); }; globiData.findStats = function (search, callback) { var req = createReq(); var uri = urlPrefix + '/reports/collections'; if (search.source) { uri = uri + '?source=' + encodeURIComponent(search.source); } req.open('GET', uri, true); req.onreadystatechange = function () { if (req.readyState === 4 && req.status === 200) { var resp = JSON.parse(req.responseText); var stats = {numberOfStudies: resp.data[0][6], totalInteractions: resp.data[0][4], totalTaxa: resp.data[0][5], numberOfDistinctSources: resp.data[0][7]}; callback(stats); } }; req.send(null); }; globiData.sendRequest = function (req, callback) { req.onreadystatechange = function () { if (req.readyState === 4 && req.status === 200) { if (callback.callback && callback.context) { callback.callback.call(callback.context, JSON.parse(req.responseText)); } else { callback(JSON.parse(req.responseText)); } } }; req.send(null); }; globiData.findInteractionTypes = function (search, callback) { if (arguments.length === 1) { callback = search; search = []; } search = search.map(function (item) { return 'taxon=' + encodeURIComponent(item); }); var urlQuery = search.length > 0 ? '?' + search.join('&') + '&type=json' : ''; var req = createReq(); req.open('GET', urlPrefix + '/interactionTypes' + urlQuery, true); globiData.sendRequest(req, callback); }; globiData.findSpeciesInteractions = function (search, callback) { var searchAlt = extend({}, search); var callbackAlt = callback; if ('d3' === searchAlt.resultType) { searchAlt.resultType = 'json'; callbackAlt = function(interactions) { callback(callbackProxyForD3(interactions)); } } var uri = globiData.urlForTaxonInteractionQuery(searchAlt); var req = createReq(); req.open('GET', uri, true); globiData.sendRequest(req, callbackAlt); }; globiData.findTaxon = function(scientificName, opts, callback) { var uri = globiData.urlForTaxonImageQuery(scientificName, opts); globiData.get(uri, callback); } globiData.findTaxonInfo = function (scientificName, callback) { globiData.findTaxon(scientificName, { lang: "en" }, callback); }; globiData.findTaxonLinks = function (scientificName, callback) { var uri = urlPrefix + '/taxonLinks/' + encodeURIComponent(scientificName); globiData.get(uri, callback); } globiData.findTaxaInfo = function (scientificNames, callback) { var uri = globiData.urlForTaxonImagesQuery(scientificNames); globiData.get(uri, callback); }; globiData.get = function (uri, callback) { var req = createReq(); req.open('GET', uri, true); globiData.sendRequest(req, callback); }; globiData.findCloseTaxonMatches = function (name, callback) { var uri = globiData.urlForFindCloseTaxonMatches(name); var req = createReq(); req.open('GET', uri, true); req.onreadystatechange = function () { if (req.readyState === 4 && req.status === 200) { var response = JSON.parse(req.responseText); var data = response.data; var closeMatches = []; data.forEach(function (element, index) { var taxonHierarchy = []; var commonNames = globiData.mapCommonNameList(element[1]); var pathString = element[2]; pathString = pathString === null ? "" : pathString; var path = pathString.split('|'); path.forEach(function (taxon, index) { taxonHierarchy[index] = taxon.trim(); }); var scientificName = element[0].trim(); closeMatches[index] = { scientificName: scientificName, commonNames: commonNames, path: taxonHierarchy}; }); callback(closeMatches); } }; req.send(null); }; /** * Transforms a common name list string into a map * f.x.: * "foo @en | bar @de" => {en: "foo", de: "bar"} * * @param {string} pipedCommonNameList * @param {boolean} [override] * @returns {Object.<string, string>} */ globiData.mapCommonNameList = function (pipedCommonNameList, override) { override = typeof override !== 'undefined' ? !!override : true; pipedCommonNameList = typeof pipedCommonNameList !== 'string' ? '' : pipedCommonNameList; var commonNameMap = { count: 0 }; var splittedByPipeList = pipedCommonNameList.split('|').map(function (item) { return item.trim(); }); splittedByPipeList.forEach(function (item) { if (typeof item !== 'undefined') { var splittedByAtItemParts = item.split('@').map(function (item) { return item.trim(); }); if (typeof splittedByAtItemParts[1] !== 'undefined') { if (override || typeof commonNameMap[splittedByAtItemParts[1]] === 'undefined') { if (typeof commonNameMap[splittedByAtItemParts[1]] === 'undefined') commonNameMap.count++; commonNameMap[splittedByAtItemParts[1]] = splittedByAtItemParts[0]; } } } }); return commonNameMap; }; globiData.findThumbnailById = function (search, callback) { search = search || {}; var uri = globiData.urlForTaxonImageByIdQuery(search); var req = createReq(); req.open('GET', uri, true); globiData.sendRequest(req, function (reponseData) { var tumbnailUrl = reponseData.thumbnailURL; callback(tumbnailUrl); }); }; var callbackProxyForD3 = function (interactions) { var columnNames = interactions.columns || []; var sourceTaxonIds = columnNames.map(function (elem, i) { if (elem.indexOf('source_') === -1) { return -1; } else { return i; } }).filter(function (i) { return i !== -1; }); var targetTaxonIds = columnNames.map(function (elem, i) { if (elem.indexOf('target_') === -1) { return -1; } else { return i; } }).filter(function (i) { return i !== -1; }); var linkIds = columnNames.map(function (elem, i) { if ((elem.indexOf('target_') === -1) && (elem.indexOf('source_') === -1)) { return i; } else { return -1; } }).filter(function (i) { return i !== -1; }); var data = interactions.data || []; var linksAndNodes = data.reduce(function (agg, row) { var sourceTaxon = sourceTaxonIds.reduce(function (sourceObj, i) { if (row[i] !== null) { sourceObj[columnNames[i].substring('source_'.length)] = row[i]; } return sourceObj; }, {}); var targetTaxon = targetTaxonIds.reduce(function (targetObj, i) { if (row[i] !== null) { targetObj[columnNames[i].substring('target_'.length)] = row[i]; } return targetObj; }, {}); var link = linkIds.reduce(function (linkObj, i) { linkObj[columnNames[i]] = row[i]; return linkObj; }, { source: hash(sourceTaxon), target: hash(targetTaxon) }); agg.linksHash[hash(link)] = link; agg.nodeHash[hash(sourceTaxon)] = sourceTaxon; agg.nodeHash[hash(targetTaxon)] = targetTaxon; return agg; }, { linksHash: {}, nodeHash: {}}); var links = Object.keys(linksAndNodes.linksHash).map(function (i) { return linksAndNodes.linksHash[i]; }); var nodes = Object.keys(linksAndNodes.nodeHash).map(function (i) { return linksAndNodes.nodeHash[i]; }); return { links: links, nodes: nodes}; } module.exports = globiData;