From 62b39b86d5606d71433cd24a8f21d14a91678ac4 Mon Sep 17 00:00:00 2001 From: Robert Forkel Date: Sat, 23 Nov 2024 11:34:20 +0100 Subject: [PATCH] various improvements --- .github/workflows/python-package.yml | 2 +- CHANGELOG.md | 7 + setup.cfg | 7 +- .../commands/glottolog_distance.py | 63 ++++ src/cldfgeojson/create.py | 7 + src/cldfgeojson/geojson.py | 56 +++- tests/fixtures/dataset/Generic-metadata.json | 308 ++++++++++++++++++ tests/fixtures/dataset/README.md | 3 + tests/fixtures/dataset/contributions.csv | 12 + tests/fixtures/dataset/languages.csv | 11 + tests/fixtures/dataset/languages.geojson | 1 + tests/fixtures/dataset/media.csv | 2 + tests/fixtures/dataset/sources.bib | 10 + .../glottolog/languoids/glottocodes.json | 1 + .../tree/abcd1234/abcd1235/abcd1236/md.ini | 24 ++ .../languoids/tree/abcd1234/abcd1235/md.ini | 32 ++ .../languoids/tree/abcd1234/abcd1237/md.ini | 8 + .../glottolog/languoids/tree/abcd1234/md.ini | 10 + .../languoids/tree/book1242/book1243/md.ini | 10 + .../glottolog/languoids/tree/book1242/md.ini | 4 + .../languoids/tree/isol1234/dial1234/md.ini | 9 + .../glottolog/languoids/tree/isol1234/md.ini | 4 + .../glottolog/references/BIBFILES.ini | 30 ++ .../glottolog/references/bibtex/a.bib | 27 ++ .../glottolog/references/bibtex/b.bib | 12 + .../glottolog/references/bibtex/hh.bib | 23 ++ .../glottolog/references/bibtex/iso6393.bib | 5 + tests/test_cli.py | 9 + tests/test_create.py | 2 +- tests/test_geojson.py | 22 ++ 30 files changed, 715 insertions(+), 6 deletions(-) create mode 100644 src/cldfgeojson/commands/glottolog_distance.py create mode 100644 tests/fixtures/dataset/Generic-metadata.json create mode 100644 tests/fixtures/dataset/README.md create mode 100644 tests/fixtures/dataset/contributions.csv create mode 100644 tests/fixtures/dataset/languages.csv create mode 100644 tests/fixtures/dataset/languages.geojson create mode 100644 tests/fixtures/dataset/media.csv create mode 100644 tests/fixtures/dataset/sources.bib create mode 100644 tests/fixtures/glottolog/languoids/glottocodes.json create mode 100644 tests/fixtures/glottolog/languoids/tree/abcd1234/abcd1235/abcd1236/md.ini create mode 100644 tests/fixtures/glottolog/languoids/tree/abcd1234/abcd1235/md.ini create mode 100644 tests/fixtures/glottolog/languoids/tree/abcd1234/abcd1237/md.ini create mode 100644 tests/fixtures/glottolog/languoids/tree/abcd1234/md.ini create mode 100644 tests/fixtures/glottolog/languoids/tree/book1242/book1243/md.ini create mode 100644 tests/fixtures/glottolog/languoids/tree/book1242/md.ini create mode 100644 tests/fixtures/glottolog/languoids/tree/isol1234/dial1234/md.ini create mode 100644 tests/fixtures/glottolog/languoids/tree/isol1234/md.ini create mode 100644 tests/fixtures/glottolog/references/BIBFILES.ini create mode 100644 tests/fixtures/glottolog/references/bibtex/a.bib create mode 100644 tests/fixtures/glottolog/references/bibtex/b.bib create mode 100644 tests/fixtures/glottolog/references/bibtex/hh.bib create mode 100644 tests/fixtures/glottolog/references/bibtex/iso6393.bib diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 3c358e0..3e253d2 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.8, 3.9, "3.10", "3.11"] + python-version: [3.9, "3.10", 3.11, 3.12] steps: - uses: actions/checkout@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md index f80b735..6249629 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changes +## unreleased + +- Dropped support for python 3.8, added support for python 3.13. +- Added command to compute distances between areas and Glottolog point coordinates. +- Added functions to write more compact GeoJSON by limiting float precision to 5 decimal places. + + ## [1.0.0] - 2024-06-19 Added function to translate GeoJSON objects to be "pacific centered". diff --git a/setup.cfg b/setup.cfg index 89d4063..58fb1ae 100644 --- a/setup.cfg +++ b/setup.cfg @@ -20,11 +20,11 @@ classifiers = Natural Language :: English Operating System :: OS Independent Programming Language :: Python :: 3 - Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.11 Programming Language :: Python :: 3.12 + Programming Language :: Python :: 3.13 Programming Language :: Python :: Implementation :: CPython Programming Language :: Python :: Implementation :: PyPy License :: OSI Approved :: Apache Software License @@ -34,11 +34,12 @@ zip_safe = False packages = find: package_dir = = src -python_requires = >=3.8 +python_requires = >=3.9 install_requires = cldfbench clldutils pycldf>=1.30.0 + pyglottolog shapely rasterio mako @@ -94,7 +95,7 @@ show_missing = true skip_covered = true [tox:tox] -envlist = py38, py39, py310, py311, py312 +envlist = py39, py310, py311, py312, py313 isolated_build = true skip_missing_interpreter = true diff --git a/src/cldfgeojson/commands/glottolog_distance.py b/src/cldfgeojson/commands/glottolog_distance.py new file mode 100644 index 0000000..5bb8747 --- /dev/null +++ b/src/cldfgeojson/commands/glottolog_distance.py @@ -0,0 +1,63 @@ +""" +Compute the distance between speaker areas in a CLDF dataset and corresponding Glottolog point +coordinate. + +To get an overview of Glottolog distances for a dataset you may pipe the output to the csvstat +tool: + +cldfbench geojson.glottolog_distance path/to/cldf --glottolog path/to/glottolog --format tsv | csvstat -t + +You can also print the distances to the terminal using a tool like termgraph: + +cldfbench geojson.glottolog_distance path/to/cldf --glottolog path/to/glottolog --format tsv | \ +sed '/^$/d' | csvcut -t -c ID,Distance | csvsort -c Distance | csvformat -E | termgraph +""" # noqa: E501 +from clldutils.clilib import Table, add_format +from shapely.geometry import Point, shape, MultiPolygon +from pycldf.cli_util import add_dataset, get_dataset, add_catalog_spec +from pycldf.media import MediaTable +from tqdm import tqdm + + +def register(parser): + add_dataset(parser) + add_catalog_spec(parser, 'glottolog') + add_format(parser, 'simple') + + +def run(args): + from cldfgeojson import MEDIA_TYPE + + ds = get_dataset(args) + + geojsons = {} + for media in MediaTable(ds): + if media.mimetype == MEDIA_TYPE: + geojsons[media.id] = { + f['properties']['cldf:languageReference']: shape(f['geometry']) + for f in media.read_json()['features'] + if f['properties'].get('cldf:languageReference')} + + gl_coords = { + lg.id: Point(float(lg.longitude), float(lg.latitude)) + for lg in args.glottolog.api.languoids() if lg.longitude} + + with Table(args, 'ID', 'Distance', 'Contained', 'NPolys') as t: + for i, lg in tqdm(enumerate(ds.objects('LanguageTable'), start=1)): + if lg.cldf.glottocode in gl_coords: + if lg.cldf.speakerArea in geojsons: + shp = geojsons[lg.cldf.speakerArea][lg.cldf.id] + else: # pragma: no cover + shp = shape(lg.speaker_area_as_geojson_feature['geometry']) + + npolys = len(shp.geoms) if isinstance(shp, MultiPolygon) else 1 + gl_coord = gl_coords[lg.cldf.glottocode] + if shp.contains(gl_coord): + t.append((lg.id, 0, True, npolys)) + elif shp.convex_hull.contains(gl_coord): + t.append((lg.id, 0, False, npolys)) # pragma: no cover + else: + dist = shp.distance(gl_coord) + if dist > 180: + dist = abs(dist - 360) # pragma: no cover + t.append((lg.id, dist, False, npolys)) diff --git a/src/cldfgeojson/create.py b/src/cldfgeojson/create.py index 3ca23c4..aa70501 100644 --- a/src/cldfgeojson/create.py +++ b/src/cldfgeojson/create.py @@ -127,11 +127,18 @@ def merged_geometry(features: typing.Iterable[typing.Union[geojson.Feature, geoj Specify `None` to add no buffer. :return: The resulting Geometry object representing the merged shapes. """ + features = list(features) + + if len(features) == 1: + f = features[0] + return f.get('geometry', f) + def get_shape(f): s = shape(f.get('geometry', f)) if buffer: s = s.buffer(buffer) return s + res = union_all([get_shape(f) for f in features]) if buffer: res = res.buffer(-buffer) diff --git a/src/cldfgeojson/geojson.py b/src/cldfgeojson/geojson.py index dd24c32..97809d5 100644 --- a/src/cldfgeojson/geojson.py +++ b/src/cldfgeojson/geojson.py @@ -1,6 +1,10 @@ +import json import typing +import collections -__all__ = ['MEDIA_TYPE', 'Geometry', 'Feature', 'pacific_centered'] +from clldutils import jsonlib + +__all__ = ['MEDIA_TYPE', 'Geometry', 'Feature', 'pacific_centered', 'dump', 'dumps'] # See https://datatracker.ietf.org/doc/html/rfc7946#section-12 MEDIA_TYPE = 'application/geo+json' @@ -80,3 +84,53 @@ def fix_position(pos): fix_position(pos) for pos in line] for line in poly] for poly in geom['coordinates']] return obj + + +# +# To make GeoJSON as small as possible, we provide functionality to write GeoJSON with coordinates +# limited to 5 decimal places, corresponding to a precision of ~1m. +# +class FloatWrapper: + """ + In order to use the extension mechanism of Python's json.JSONEncode, we have to wrap floats in + an "unknown" type. + """ + def __init__(self, value): + self.value = value + + +def wrap_floats(obj, in_coordinates=False): + """ + Turns a GeoJSON object into one with all coordinates wrapped in FloatWrapper instances. + + :param obj: + :param in_coordinates: + :return: + """ + if isinstance(obj, (list, tuple)): + return [wrap_floats(item, in_coordinates=in_coordinates) for item in obj] + if isinstance(obj, dict): + # Detect whether we are in the "coordinates" array of a GeoJSON object. + return collections.OrderedDict( + (k, wrap_floats(v, in_coordinates=True if k == 'coordinates' else in_coordinates)) + for k, v in obj.items()) + if isinstance(obj, float) and in_coordinates: + return FloatWrapper(obj) + return obj + + +class MeterPrecisionFloatEncoder(json.JSONEncoder): + def default(self, obj): + if isinstance(obj, FloatWrapper): + return round(obj.value, 5) + return super().default(obj) + + +def dump(obj, *args, **kw): + kw['cls'] = MeterPrecisionFloatEncoder + return jsonlib.dump(wrap_floats(obj), *args, **kw) + + +def dumps(obj, **kw): + kw['cls'] = MeterPrecisionFloatEncoder + return json.dumps(wrap_floats(obj), **kw) diff --git a/tests/fixtures/dataset/Generic-metadata.json b/tests/fixtures/dataset/Generic-metadata.json new file mode 100644 index 0000000..2ba65bf --- /dev/null +++ b/tests/fixtures/dataset/Generic-metadata.json @@ -0,0 +1,308 @@ +{ + "@context": [ + "http://www.w3.org/ns/csvw", + { + "@language": "en" + } + ], + "dc:bibliographicCitation": "Zucchi, Alberta. 2017. Arqueolog\u00eda de los llanos occidentales y el Orinoco. (Collecci\u00f3n cl\u00e1sicos de la arqueolog\u00eda Venezolana.) Caracas: Centro Nacional de Estudios Hist\u00f3ricos.", + "dc:conformsTo": "http://cldf.clld.org/v1.0/terms.rdf#Generic", + "dc:description": "This dataset provides non-overlapping, approximate, contemporary ranges for several Arawakan groups based on map 10 in Zucchi 2012.", + "dc:license": "https://creativecommons.org/licenses/by/4.0/", + "dc:source": "sources.bib", + "dc:spatial": "westlimit=-70.8; southlimit=-0.7; eastlimit=-63.3; northlimit=6.5", + "dc:title": "Glottography dataset derived from Zucchi 2017 \"Arqueolog\u00eda de los llanos occidentales y el Orinoco\"", + "dcat:accessURL": "https://github.com/Glottography/zucchi2017arqueologia", + "prov:wasDerivedFrom": [ + { + "rdf:about": "https://github.com/Glottography/zucchi2017arqueologia", + "rdf:type": "prov:Entity", + "dc:created": "074a334", + "dc:title": "Repository" + }, + { + "rdf:about": "https://github.com/glottolog/glottolog", + "rdf:type": "prov:Entity", + "dc:created": "v5.1", + "dc:title": "Glottolog" + } + ], + "prov:wasGeneratedBy": [ + { + "dc:title": "python", + "dc:description": "3.12.3" + }, + { + "dc:title": "python-packages", + "dc:relation": "requirements.txt" + } + ], + "rdf:ID": "zucchi2017arqueologia", + "rdf:type": "http://www.w3.org/ns/dcat#Distribution", + "tables": [ + { + "dc:conformsTo": "http://cldf.clld.org/v1.0/terms.rdf#MediaTable", + "dc:extent": 3, + "tableSchema": { + "columns": [ + { + "datatype": { + "base": "string", + "format": "[a-zA-Z0-9_\\-]+" + }, + "propertyUrl": "http://cldf.clld.org/v1.0/terms.rdf#id", + "required": true, + "name": "ID" + }, + { + "datatype": "string", + "propertyUrl": "http://cldf.clld.org/v1.0/terms.rdf#name", + "required": false, + "name": "Name" + }, + { + "datatype": "string", + "propertyUrl": "http://cldf.clld.org/v1.0/terms.rdf#description", + "required": false, + "name": "Description" + }, + { + "datatype": { + "base": "string", + "format": "[^/]+/.+" + }, + "propertyUrl": "http://cldf.clld.org/v1.0/terms.rdf#mediaType", + "required": true, + "name": "Media_Type" + }, + { + "datatype": "anyURI", + "propertyUrl": "http://cldf.clld.org/v1.0/terms.rdf#downloadUrl", + "required": false, + "name": "Download_URL" + }, + { + "datatype": "string", + "propertyUrl": "http://cldf.clld.org/v1.0/terms.rdf#pathInZip", + "required": false, + "name": "Path_In_Zip" + } + ], + "primaryKey": [ + "ID" + ] + }, + "url": "media.csv" + }, + { + "dc:conformsTo": "http://cldf.clld.org/v1.0/terms.rdf#LanguageTable", + "dc:extent": 12, + "tableSchema": { + "columns": [ + { + "datatype": { + "base": "string", + "format": "[a-zA-Z0-9_\\-]+" + }, + "propertyUrl": "http://cldf.clld.org/v1.0/terms.rdf#id", + "required": true, + "name": "ID" + }, + { + "datatype": "string", + "propertyUrl": "http://cldf.clld.org/v1.0/terms.rdf#name", + "required": false, + "name": "Name" + }, + { + "datatype": "string", + "propertyUrl": "http://cldf.clld.org/v1.0/terms.rdf#macroarea", + "required": false, + "name": "Macroarea" + }, + { + "datatype": { + "base": "decimal", + "minimum": "-90", + "maximum": "90" + }, + "propertyUrl": "http://cldf.clld.org/v1.0/terms.rdf#latitude", + "required": false, + "name": "Latitude" + }, + { + "datatype": { + "base": "decimal", + "minimum": "-180", + "maximum": "180" + }, + "propertyUrl": "http://cldf.clld.org/v1.0/terms.rdf#longitude", + "required": false, + "name": "Longitude" + }, + { + "datatype": { + "base": "string", + "format": "[a-z0-9]{4}[1-9][0-9]{3}" + }, + "propertyUrl": "http://cldf.clld.org/v1.0/terms.rdf#glottocode", + "required": false, + "valueUrl": "http://glottolog.org/resource/languoid/id/{Glottocode}", + "name": "Glottocode" + }, + { + "datatype": { + "base": "string", + "format": "[a-z]{3}" + }, + "propertyUrl": "http://cldf.clld.org/v1.0/terms.rdf#iso639P3code", + "required": false, + "name": "ISO639P3code" + }, + { + "dc:description": "List of identifiers of features that were aggregated to create the feature referenced by Speaker_Area.", + "propertyUrl": "http://cldf.clld.org/v1.0/terms.rdf#contributionReference", + "separator": " ", + "name": "Feature_IDs" + }, + { + "dc:description": "https://glottolog.org/meta/glossary#Languoid", + "datatype": { + "base": "string", + "format": "dialect|language|family" + }, + "name": "Glottolog_Languoid_Level" + }, + { + "dc:description": "Name of the top-level family for the languoid in the Glottolog classification. A null value in this column marks 1) top-level families in case Glottolog_Languoid_Level is 'family' and 2) isolates in case Glottolog_Languoid_Level is 'language'.", + "name": "Family" + }, + { + "propertyUrl": "http://cldf.clld.org/v1.0/terms.rdf#speakerArea", + "name": "Speaker_Area" + } + ], + "foreignKeys": [ + { + "columnReference": [ + "Speaker_Area" + ], + "reference": { + "resource": "media.csv", + "columnReference": [ + "ID" + ] + } + }, + { + "columnReference": [ + "Feature_IDs" + ], + "reference": { + "resource": "contributions.csv", + "columnReference": [ + "ID" + ] + } + } + ], + "primaryKey": [ + "ID" + ] + }, + "url": "languages.csv" + }, + { + "dc:conformsTo": "http://cldf.clld.org/v1.0/terms.rdf#ContributionTable", + "dc:description": "We list the individual features from the source dataset as contributions in order to preserve the original metadata and a point of reference for the aggregated shapes.", + "dc:extent": 11, + "tableSchema": { + "columns": [ + { + "datatype": { + "base": "string", + "format": "[a-zA-Z0-9_\\-]+" + }, + "propertyUrl": "http://cldf.clld.org/v1.0/terms.rdf#id", + "required": true, + "name": "ID" + }, + { + "datatype": "string", + "propertyUrl": "http://cldf.clld.org/v1.0/terms.rdf#name", + "required": false, + "name": "Name" + }, + { + "datatype": "string", + "propertyUrl": "http://cldf.clld.org/v1.0/terms.rdf#description", + "required": false, + "name": "Description" + }, + { + "datatype": "string", + "propertyUrl": "http://cldf.clld.org/v1.0/terms.rdf#contributor", + "required": false, + "name": "Contributor" + }, + { + "datatype": "string", + "propertyUrl": "http://cldf.clld.org/v1.0/terms.rdf#citation", + "required": false, + "name": "Citation" + }, + { + "dc:description": "References a Glottolog languoid most closely matching the linguistic entity described by the feature.", + "datatype": { + "base": "string", + "format": "[a-z0-9]{4}[1-9][0-9]{3}" + }, + "propertyUrl": "http://cldf.clld.org/v1.0/terms.rdf#glottocode", + "valueUrl": "http://glottolog.org/resource/languoid/id/{Glottocode}", + "name": "Glottocode" + }, + { + "dc:description": "The time period to which the feature relates, specified as year AD or with the keyword 'traditional', meaning either the time of contact with European maritime powers or period when an ancient language was spoken.", + "datatype": { + "base": "string", + "format": "[0-9]{3,4}|traditional" + }, + "propertyUrl": "http://purl.org/dc/terms/temporal", + "name": "Year" + }, + { + "propertyUrl": "http://cldf.clld.org/v1.0/terms.rdf#source", + "separator": ";", + "name": "Source" + }, + { + "dc:description": "Features are linked to GeoJSON files that store the geo data.", + "propertyUrl": "http://cldf.clld.org/v1.0/terms.rdf#mediaReference", + "name": "Media_ID" + }, + { + "dc:description": "Name of the map as given in the source publication.", + "name": "Map_Name" + } + ], + "foreignKeys": [ + { + "columnReference": [ + "Media_ID" + ], + "reference": { + "resource": "media.csv", + "columnReference": [ + "ID" + ] + } + } + ], + "primaryKey": [ + "ID" + ] + }, + "url": "contributions.csv" + } + ] +} \ No newline at end of file diff --git a/tests/fixtures/dataset/README.md b/tests/fixtures/dataset/README.md new file mode 100644 index 0000000..efee9e3 --- /dev/null +++ b/tests/fixtures/dataset/README.md @@ -0,0 +1,3 @@ +# CLDF directory + +This directory contains the dataset formatted as [CLDF dataset](https://cldf.clld.org). diff --git a/tests/fixtures/dataset/contributions.csv b/tests/fixtures/dataset/contributions.csv new file mode 100644 index 0000000..592aca2 --- /dev/null +++ b/tests/fixtures/dataset/contributions.csv @@ -0,0 +1,12 @@ +ID,Name,Description,Contributor,Citation,Glottocode,Year,Source,Media_ID,Map_Name +1,Baniba,,,,guar1293,2017,zucchi2017arqueologia,,Lámina 10. Localización de algunos grupos Arawacos. +2,Bare,,,,bare1276,2017,zucchi2017arqueologia,,Lámina 10. Localización de algunos grupos Arawacos. +3,Curripaco,,,,curr1243,2017,zucchi2017arqueologia,,Lámina 10. Localización de algunos grupos Arawacos. +4,Guarequena,,,,guar1293,2017,zucchi2017arqueologia,,Lámina 10. Localización de algunos grupos Arawacos. +5,Guinao,,,,guin1258,2017,zucchi2017arqueologia,,Lámina 10. Localización de algunos grupos Arawacos. +6,Guipunave,,,,puin1248,2017,zucchi2017arqueologia,,Lámina 10. Localización de algunos grupos Arawacos. +7,Maipure,,,,maip1246,2017,zucchi2017arqueologia,,Lámina 10. Localización de algunos grupos Arawacos. +8,Mandahuaca,,,,mand1448,2017,zucchi2017arqueologia,,Lámina 10. Localización de algunos grupos Arawacos. +9,Mawakwa,,,,mawa1268,2017,zucchi2017arqueologia,,Lámina 10. Localización de algunos grupos Arawacos. +10,Piapoco,,,,piap1246,2017,zucchi2017arqueologia,,Lámina 10. Localización de algunos grupos Arawacos. +11,Yavitero,,,,yavi1245,2017,zucchi2017arqueologia,,Lámina 10. Localización de algunos grupos Arawacos. diff --git a/tests/fixtures/dataset/languages.csv b/tests/fixtures/dataset/languages.csv new file mode 100644 index 0000000..67d429b --- /dev/null +++ b/tests/fixtures/dataset/languages.csv @@ -0,0 +1,11 @@ +ID,Name,Macroarea,Latitude,Longitude,Glottocode,ISO639P3code,Feature_IDs,Glottolog_Languoid_Level,Family,Speaker_Area +bare1276,Baré,,1.91649,-66.828,abcd1234,,2,language,Arawakan,languages +curr1243,Curripaco,,0.69618,-67.5028,abcd1235,,3,language,Arawakan,languages +guar1293,Baniva de Maroa,,1.80835,-66.922505,abcd1236,,1 4,language,Arawakan,languages +guin1258,Guinau,,4.797607,-64.73877,,,5,language,Arawakan,languages +maip1247,Maipure-Avane,,4.8,-67.5,,,7,language,Arawakan,languages +mand1448,Mandahuaca,,1.48,-66.52,abcd1235,,8,language,Arawakan,languages +mawa1268,Mawakwa,,3.11,-66.238404,,,9,language,Bookkeeping,languages +piap1246,Piapoco,,4.37718,-68.5953,,,10,language,Arawakan,languages +puin1248,Puinave,,3.92974,-67.6886,,,6,language,,languages +yavi1244,Yavitero-Pareni,,2.924844,-67.438886,,,11,language,Arawakan,languages diff --git a/tests/fixtures/dataset/languages.geojson b/tests/fixtures/dataset/languages.geojson new file mode 100644 index 0000000..18f3719 --- /dev/null +++ b/tests/fixtures/dataset/languages.geojson @@ -0,0 +1 @@ +{"type": "FeatureCollection", "features": [{"type": "Feature", "properties": {"title": "Bar\u00e9", "fill": "#CC5151", "family": "Arawakan", "cldf:languageReference": "bare1276", "fill-opacity": 0.5}, "geometry": {"type": "Polygon", "coordinates": [[[-65.74237, -0.53261], [-65.69057, -0.40001], [-65.60147, -0.19902], [-65.59318, 0.15737], [-65.58282, 0.55312], [-65.58282, 0.82247], [-65.51237, 1.06279], [-65.42949, 1.22438], [-65.30102, 1.10423], [-65.08553, 1.02136], [-64.91562, 0.9965], [-64.68356, 1.01721], [-64.51365, 1.11666], [-64.41419, 1.15809], [-64.11582, 1.02964], [-63.82159, 0.77689], [-63.54808, 0.44952], [-63.41547, 0.21746], [-63.31186, -0.05191], [-63.30358, -0.1928], [-63.36574, -0.41244], [-63.46934, -0.5409], [-63.63096, -0.63206], [-63.79672, -0.66936], [-63.99149, -0.68593], [-64.30644, -0.6445], [-64.49293, -0.65693], [-64.67112, -0.6735], [-64.90319, -0.69008], [-65.23057, -0.6072], [-65.4585, -0.5409], [-65.74237, -0.53261]]]}}, {"type": "Feature", "properties": {"title": "Curripaco", "fill": "#CC5151", "family": "Arawakan", "cldf:languageReference": "curr1243", "fill-opacity": 0.5}, "geometry": {"type": "Polygon", "coordinates": [[[-69.41226, 2.02785], [-69.19616, 2.10311], [-68.88182, 2.13583], [-68.68863, 2.12928], [-68.42341, 2.1162], [-68.18766, 2.198], [-68.0043, 2.38121], [-67.8504, 2.44337], [-67.67686, 2.39757], [-67.54589, 2.40739], [-67.62447, 2.28306], [-67.68669, 2.12601], [-67.68669, 1.98531], [-67.56554, 1.82168], [-67.41164, 1.69077], [-67.30686, 1.47474], [-67.29377, 1.31108], [-67.30031, 1.14085], [-67.24792, 1.0099], [-67.20536, 0.97389], [-67.29377, 0.80692], [-67.38545, 0.4926], [-67.38545, 0.20446], [-67.28722, -0.03784], [-67.54916, -0.00509], [-67.77182, -0.02474], [-68.02394, -0.04766], [-68.25642, -0.08695], [-68.49872, -0.09677], [-68.75085, -0.07385], [-69.21253, -0.06076], [-69.44828, -0.05748], [-69.77571, -0.00182], [-70.04748, 0.07022], [-70.2554, 0.18973], [-70.41585, 0.35672], [-70.57629, 0.57282], [-70.66306, 0.70378], [-70.70235, 0.80528], [-70.74492, 0.88058], [-70.74328, 1.08029], [-70.56647, 1.24397], [-70.22266, 1.45347], [-70.00164, 1.57867], [-69.71186, 1.76768], [-69.52768, 1.9125], [-69.41226, 2.02785]]]}}, {"type": "Feature", "properties": {"title": "Baniva de Maroa", "fill": "#CC5151", "family": "Arawakan", "cldf:languageReference": "guar1293", "fill-opacity": 0.5}, "geometry": {"type": "Polygon", "coordinates": [[[-70.11842, 2.50825], [-70.1184, 2.50838], [-70.09007, 2.63899], [-70.09004, 2.63909], [-70.08999, 2.63918], [-70.0028, 2.77854], [-70.00273, 2.77864], [-70.00263, 2.7787], [-69.89807, 2.8418], [-69.89795, 2.84186], [-69.89783, 2.8419], [-69.78676, 2.868], [-69.78663, 2.86802], [-69.78649, 2.86803], [-69.54003, 2.87021], [-69.53989, 2.87021], [-69.35672, 2.8615], [-69.3566, 2.86148], [-69.35651, 2.86141], [-69.2827, 2.79401], [-69.28232, 2.7937], [-69.28191, 2.79342], [-69.28147, 2.79318], [-69.28101, 2.79299], [-69.28053, 2.79285], [-69.28005, 2.79276], [-69.27955, 2.79271], [-69.27906, 2.79271], [-69.27856, 2.79276], [-69.27807, 2.79286], [-69.2776, 2.79301], [-69.27714, 2.79321], [-69.11028, 2.8744], [-69.10994, 2.87458], [-69.10961, 2.87479], [-68.95964, 2.97899], [-68.95932, 2.97923], [-68.95902, 2.97949], [-68.84153, 3.09247], [-68.84143, 3.09256], [-68.84131, 3.09261], [-68.60689, 3.17497], [-68.60643, 3.17516], [-68.60598, 3.17539], [-68.60557, 3.17567], [-68.60518, 3.17599], [-68.60483, 3.17634], [-68.549, 3.23851], [-68.54892, 3.23859], [-68.54883, 3.23866], [-68.37019, 3.35175], [-68.36969, 3.35211], [-68.28488, 3.42158], [-68.2848, 3.42164], [-68.2847, 3.42169], [-68.18043, 3.4694], [-68.18003, 3.4696], [-68.17965, 3.46984], [-68.09278, 3.53054], [-68.09262, 3.53065], [-67.99239, 3.60677], [-67.99229, 3.60684], [-67.99216, 3.60685], [-67.8658, 3.6112], [-67.86568, 3.6112], [-67.86558, 3.61114], [-67.76101, 3.54809], [-67.76091, 3.54802], [-67.76088, 3.5479], [-67.72599, 3.389], [-67.72597, 3.38892], [-67.6913, 3.20072], [-67.69118, 3.2002], [-67.69099, 3.19969], [-67.69076, 3.19921], [-67.69048, 3.19875], [-67.69014, 3.19833], [-67.61477, 3.11231], [-67.61455, 3.11204], [-67.54124, 3.00006], [-67.54096, 2.99968], [-67.54064, 2.99932], [-67.5403, 2.99899], [-67.53992, 2.9987], [-67.53952, 2.99845], [-67.53909, 2.99823], [-67.49364, 2.97793], [-67.49319, 2.97775], [-67.49273, 2.97762], [-67.49225, 2.97754], [-67.49177, 2.9775], [-67.49128, 2.9775], [-67.4908, 2.97756], [-67.49033, 2.97766], [-67.48987, 2.97781], [-67.48942, 2.978], [-67.489, 2.97823], [-67.4886, 2.9785], [-67.48823, 2.97881], [-67.48788, 2.97915], [-67.48758, 2.97953], [-67.48731, 2.97993], [-67.48708, 2.98036], [-67.4869, 2.98081], [-67.48676, 2.98127], [-67.48666, 2.98174], [-67.48661, 2.98222], [-67.48393, 3.03183], [-67.48391, 3.03195], [-67.48383, 3.03203], [-67.36307, 3.14644], [-67.36272, 3.1468], [-67.36242, 3.14719], [-67.30365, 3.23056], [-67.22913, 3.33597], [-67.22905, 3.33606], [-67.22894, 3.3361], [-67.06134, 3.37948], [-67.06122, 3.3795], [-67.06111, 3.37949], [-66.8873, 3.3578], [-66.88717, 3.35778], [-66.88708, 3.3577], [-66.78161, 3.2648], [-66.7814, 3.26459], [-66.67151, 3.14269], [-66.67118, 3.14235], [-66.67082, 3.14205], [-66.67043, 3.14178], [-66.67002, 3.14155], [-66.66959, 3.14137], [-66.66915, 3.14122], [-66.66869, 3.14111], [-66.66822, 3.14105], [-66.66775, 3.14103], [-66.66728, 3.14106], [-66.66682, 3.14113], [-66.57667, 3.15913], [-66.57607, 3.15929], [-66.46459, 3.19639], [-66.46448, 3.19643], [-66.4644, 3.19634], [-66.39378, 3.10436], [-66.39345, 3.10397], [-66.39308, 3.10362], [-66.39269, 3.10331], [-66.39226, 3.10304], [-66.3918, 3.10282], [-66.32225, 3.07262], [-66.32175, 3.07243], [-66.32123, 3.0723], [-66.32069, 3.07223], [-66.17889, 3.05991], [-66.17818, 3.0599], [-66.06676, 3.06608], [-66.06664, 3.06608], [-66.06653, 3.06607], [-66.04635, 3.06356], [-66.04585, 3.06352], [-66.04536, 3.06353], [-66.04486, 3.06359], [-66.04438, 3.0637], [-66.04391, 3.06386], [-66.04346, 3.06406], [-66.04303, 3.06431], [-66.04262, 3.0646], [-66.04225, 3.06492], [-66.04191, 3.06529], [-66.04161, 3.06568], [-66.04135, 3.0661], [-66.04113, 3.06655], [-66.04096, 3.06701], [-66.04083, 3.06749], [-66.01383, 3.19631], [-66.0138, 3.19643], [-66.01368, 3.19643], [-65.95799, 3.19334], [-65.95786, 3.19332], [-65.95775, 3.19327], [-65.84672, 3.13785], [-65.84621, 3.13763], [-65.84568, 3.13746], [-65.84514, 3.13736], [-65.77461, 3.12818], [-65.7745, 3.12816], [-65.77459, 3.1281], [-65.91961, 3.04491], [-65.92006, 3.04462], [-65.92048, 3.04427], [-65.92086, 3.04389], [-65.9212, 3.04347], [-65.97179, 2.97215], [-65.97206, 2.97172], [-65.97229, 2.97126], [-65.97247, 2.97079], [-65.9726, 2.9703], [-65.97268, 2.96979], [-65.97271, 2.96929], [-65.97269, 2.96878], [-65.97261, 2.96827], [-65.97249, 2.96778], [-65.97231, 2.9673], [-65.93953, 2.88992], [-65.93929, 2.88943], [-65.93901, 2.88898], [-65.93867, 2.88856], [-65.89267, 2.83649], [-65.8926, 2.8364], [-65.89264, 2.83629], [-65.90808, 2.80236], [-65.90814, 2.80226], [-65.90825, 2.80224], [-66.01575, 2.79304], [-66.0162, 2.79298], [-66.01665, 2.79287], [-66.01709, 2.79273], [-66.01751, 2.79255], [-66.01791, 2.79233], [-66.10323, 2.74059], [-66.10368, 2.74028], [-66.1041, 2.73992], [-66.10447, 2.73952], [-66.14897, 2.68619], [-66.14928, 2.68578], [-66.14954, 2.68534], [-66.14976, 2.68487], [-66.14993, 2.68439], [-66.15005, 2.68389], [-66.15011, 2.68339], [-66.15013, 2.68287], [-66.15009, 2.68236], [-66.15, 2.68186], [-66.14126, 2.64404], [-66.14124, 2.64392], [-66.14136, 2.6439], [-66.31173, 2.62224], [-66.31218, 2.62216], [-66.31261, 2.62205], [-66.43819, 2.58227], [-66.43865, 2.5821], [-66.43908, 2.58189], [-66.43949, 2.58164], [-66.43987, 2.58135], [-66.44023, 2.58103], [-66.44055, 2.58067], [-66.46606, 2.54953], [-66.46635, 2.54913], [-66.46661, 2.5487], [-66.46682, 2.54825], [-66.46698, 2.54778], [-66.4671, 2.54729], [-66.46717, 2.5468], [-66.46719, 2.5463], [-66.46716, 2.5458], [-66.46708, 2.54531], [-66.45843, 2.50501], [-66.45829, 2.50448], [-66.45809, 2.50397], [-66.45783, 2.50348], [-66.42103, 2.4422], [-66.42097, 2.44209], [-66.42097, 2.44196], [-66.42406, 2.40496], [-66.42408, 2.40483], [-66.42419, 2.4048], [-66.49232, 2.38623], [-66.49245, 2.3862], [-66.49258, 2.38622], [-66.56073, 2.39757], [-66.56123, 2.39762], [-66.56173, 2.39763], [-66.56223, 2.39759], [-66.56273, 2.39749], [-66.56321, 2.39735], [-66.56368, 2.39716], [-66.56412, 2.39692], [-66.56454, 2.39664], [-66.56493, 2.39632], [-66.56528, 2.39596], [-66.5656, 2.39557], [-66.56587, 2.39514], [-66.5661, 2.39469], [-66.56629, 2.39422], [-66.56642, 2.39374], [-66.56651, 2.39324], [-66.56655, 2.39274], [-66.56653, 2.39224], [-66.56095, 2.32258], [-66.56089, 2.32207], [-66.56077, 2.32156], [-66.56059, 2.32108], [-66.56037, 2.32061], [-66.56011, 2.32017], [-66.5598, 2.31976], [-66.49563, 2.24343], [-66.49556, 2.24334], [-66.49555, 2.24322], [-66.49246, 2.15672], [-66.49239, 2.15605], [-66.47693, 2.06643], [-66.47691, 2.06631], [-66.47697, 2.06621], [-66.54199, 1.97029], [-66.54232, 1.96972], [-66.5732, 1.908], [-66.57326, 1.9079], [-66.57338, 1.90788], [-66.64462, 1.89859], [-66.64474, 1.89858], [-66.64482, 1.89866], [-66.69756, 1.95757], [-66.6976, 1.95762], [-66.74909, 2.01816], [-66.74943, 2.01852], [-66.74979, 2.01884], [-66.75018, 2.01912], [-66.7506, 2.01936], [-66.75104, 2.01956], [-66.7515, 2.01972], [-66.75197, 2.01984], [-66.75245, 2.0199], [-66.81743, 2.02581], [-66.81796, 2.02583], [-66.8185, 2.02579], [-66.81902, 2.02569], [-66.81954, 2.02554], [-66.82003, 2.02534], [-66.88394, 1.99493], [-66.88407, 1.99488], [-66.8842, 1.99488], [-66.92123, 1.99796], [-66.92136, 1.99798], [-66.92147, 1.99805], [-66.97793, 2.03665], [-66.97835, 2.03691], [-66.97879, 2.03713], [-66.97925, 2.0373], [-66.97973, 2.03742], [-66.98022, 2.0375], [-66.98071, 2.03753], [-66.9812, 2.03751], [-66.98169, 2.03744], [-66.98217, 2.03732], [-66.98263, 2.03716], [-66.98308, 2.03695], [-67.03897, 2.00755], [-67.03945, 2.00727], [-67.03989, 2.00693], [-67.10464, 1.95146], [-67.10474, 1.95139], [-67.10485, 1.95134], [-67.16989, 1.92968], [-67.17, 1.92965], [-67.17001, 1.92976], [-67.17311, 2.14392], [-67.17311, 2.14399], [-67.17001, 2.36132], [-67.17, 2.36139], [-67.16387, 2.5084], [-67.16388, 2.50887], [-67.16392, 2.50935], [-67.16402, 2.50982], [-67.16416, 2.51028], [-67.16434, 2.51072], [-67.16456, 2.51114], [-67.16482, 2.51154], [-67.16512, 2.51191], [-67.21032, 2.56309], [-67.2104, 2.56319], [-67.21041, 2.56332], [-67.21041, 2.67068], [-67.21043, 2.67114], [-67.2105, 2.6716], [-67.2106, 2.67205], [-67.21075, 2.67249], [-67.21094, 2.67292], [-67.263, 2.77692], [-67.26327, 2.7774], [-67.26359, 2.77784], [-67.3437, 2.87631], [-67.34408, 2.87673], [-67.34451, 2.8771], [-67.39857, 2.9191], [-67.39898, 2.91938], [-67.39941, 2.91963], [-67.39987, 2.91982], [-67.40034, 2.91998], [-67.40082, 2.92008], [-67.40132, 2.92014], [-67.40181, 2.92015], [-67.49001, 2.91711], [-67.49013, 2.91711], [-67.49013, 2.91713], [-67.49015, 2.91757], [-67.49022, 2.91806], [-67.49034, 2.91854], [-67.4905, 2.919], [-67.49071, 2.91945], [-67.49096, 2.91987], [-67.49125, 2.92026], [-67.49158, 2.92063], [-67.49194, 2.92096], [-67.49234, 2.92126], [-67.49276, 2.92151], [-67.4932, 2.92172], [-67.49367, 2.92189], [-67.49414, 2.92201], [-67.49463, 2.92208], [-67.49512, 2.92211], [-67.49561, 2.92208], [-67.4961, 2.92201], [-67.49657, 2.92189], [-67.49704, 2.92173], [-67.49748, 2.92152], [-67.4979, 2.92127], [-67.4983, 2.92098], [-67.49866, 2.92065], [-67.58447, 2.83494], [-67.58479, 2.8346], [-67.58507, 2.83422], [-67.58532, 2.83382], [-67.58553, 2.8334], [-67.58569, 2.83296], [-67.58582, 2.83251], [-67.5859, 2.83204], [-67.58594, 2.83157], [-67.58593, 2.8311], [-67.58588, 2.83064], [-67.57104, 2.73533], [-67.57091, 2.73474], [-67.5317, 2.59548], [-67.50773, 2.51057], [-67.5077, 2.51043], [-67.5077, 2.51029], [-67.51423, 2.41241], [-67.51424, 2.4123], [-67.51435, 2.41226], [-67.55341, 2.40142], [-67.55353, 2.40139], [-67.55365, 2.40143], [-67.67519, 2.44263], [-67.67578, 2.44279], [-67.67638, 2.44288], [-67.85564, 2.45798], [-67.85615, 2.458], [-67.85667, 2.45796], [-67.85717, 2.45787], [-67.85767, 2.45773], [-67.85815, 2.45754], [-68.01777, 2.38427], [-68.01823, 2.38403], [-68.01866, 2.38374], [-68.01907, 2.38341], [-68.1275, 2.28373], [-68.12778, 2.28351], [-68.3087, 2.15936], [-68.30881, 2.15929], [-68.30894, 2.15926], [-68.52043, 2.1244], [-68.52055, 2.12438], [-68.52067, 2.12438], [-68.71906, 2.13092], [-68.71933, 2.13092], [-68.93936, 2.12656], [-68.93997, 2.12652], [-69.10771, 2.10257], [-69.10778, 2.10256], [-69.34334, 2.0655], [-69.34366, 2.06544], [-69.41103, 2.05024], [-69.41117, 2.05022], [-69.41132, 2.05021], [-69.57699, 2.05239], [-69.57715, 2.05239], [-69.6992, 2.05021], [-69.69931, 2.05021], [-69.69942, 2.05024], [-69.84983, 2.10253], [-69.84993, 2.10257], [-69.85002, 2.10261], [-69.91748, 2.13958], [-69.9176, 2.13965], [-69.91771, 2.13974], [-69.99829, 2.21156], [-69.99836, 2.21163], [-69.99843, 2.21171], [-70.08125, 2.33368], [-70.08131, 2.33378], [-70.08134, 2.33389], [-70.1184, 2.50812], [-70.11842, 2.50825]]]}}, {"type": "Feature", "properties": {"title": "Guinau", "fill": "#CC5151", "family": "Arawakan", "cldf:languageReference": "guin1258", "fill-opacity": 0.5}, "geometry": {"type": "Polygon", "coordinates": [[[-65.21674, 5.38507], [-65.18182, 5.71531], [-65.05958, 6.04971], [-64.7758, 6.32749], [-64.55751, 6.40559], [-64.29993, 6.38823], [-64.09037, 6.219], [-63.87208, 5.84128], [-63.81096, 5.49372], [-63.81969, 5.30248], [-63.86772, 5.0242], [-63.99432, 4.77626], [-64.15586, 4.57176], [-64.35668, 4.44119], [-64.53568, 4.39331], [-64.81509, 4.48036], [-65.07267, 4.711], [-65.19055, 5.02855], [-65.21238, 5.21988], [-65.21674, 5.38507]]]}}, {"type": "Feature", "properties": {"title": "Maipure-Avane", "fill": "#CC5151", "family": "Arawakan", "cldf:languageReference": "maip1247", "fill-opacity": 0.5}, "geometry": {"type": "Polygon", "coordinates": [[[-67.4434, 3.98847], [-67.45093, 3.98638], [-67.6081, 4.04517], [-67.67359, 4.02884], [-67.73253, 4.04191], [-67.8635, 4.10723], [-67.93554, 4.16601], [-68.03377, 4.18887], [-68.08615, 4.2188], [-68.07961, 4.31676], [-67.97701, 4.42777], [-67.89406, 4.48], [-67.91589, 4.57574], [-67.93117, 4.65843], [-67.8766, 4.73239], [-67.88315, 4.81941], [-67.88533, 4.92598], [-67.76309, 4.9934], [-67.60374, 4.97818], [-67.49241, 4.91076], [-67.41601, 4.81941], [-67.33524, 4.73457], [-67.23264, 4.63884], [-67.14315, 4.5801], [-67.02964, 4.5257], [-66.89648, 4.49523], [-66.69784, 4.44518], [-66.49483, 4.37553], [-66.33766, 4.295], [-66.23506, 4.20139], [-66.1543, 4.05334], [-66.16084, 3.87477], [-66.28854, 3.61393], [-66.39005, 3.45052], [-66.41624, 3.35246], [-66.44571, 3.18247], [-66.55704, 3.16613], [-66.69784, 3.22824], [-66.81244, 3.31651], [-66.82554, 3.44071], [-66.8681, 3.57471], [-66.86155, 3.65967], [-66.94996, 3.7479], [-66.99907, 3.83938], [-67.02527, 3.93411], [-67.08051, 3.99212], [-67.14592, 3.97851], [-67.27646, 3.98491], [-67.37902, 3.96863], [-67.4434, 3.98847]]]}}, {"type": "Feature", "properties": {"title": "Mandahuaca", "fill": "#CC5151", "family": "Arawakan", "cldf:languageReference": "mand1448", "fill-opacity": 0.5}, "geometry": {"type": "Polygon", "coordinates": [[[-65.75096, -0.53515], [-65.97935, -0.55234], [-66.1709, -0.58427], [-66.41647, -0.53761], [-66.64731, -0.42465], [-66.78975, -0.31414], [-66.97638, -0.19872], [-67.21705, -0.11277], [-67.33738, 0.00265], [-67.40614, 0.21384], [-67.39632, 0.48397], [-67.31773, 0.75163], [-67.14829, 1.0512], [-67.05466, 1.30439], [-67.07953, 1.52258], [-67.14859, 1.70209], [-67.18451, 1.90643], [-67.10163, 1.99754], [-67.0077, 2.04172], [-66.94139, 2.01687], [-66.8889, 1.99754], [-66.83917, 2.01963], [-66.77839, 2.0362], [-66.71485, 2.01135], [-66.66236, 1.92023], [-66.59881, 1.9009], [-66.56013, 1.94784], [-66.49659, 2.03068], [-66.48002, 2.15353], [-66.52146, 2.24878], [-66.5256, 2.30054], [-66.55668, 2.3171], [-66.55461, 2.39474], [-66.47794, 2.4289], [-66.44168, 2.44132], [-66.44894, 2.49307], [-66.47173, 2.52412], [-66.47484, 2.57691], [-66.41164, 2.61934], [-66.35051, 2.61934], [-66.2811, 2.64625], [-66.23033, 2.64314], [-66.16299, 2.67522], [-66.12155, 2.73525], [-66.06043, 2.77353], [-66.01588, 2.80768], [-65.90399, 2.79733], [-65.89777, 2.81286], [-65.91331, 2.85942], [-65.97237, 2.9215], [-65.97237, 2.96806], [-65.94439, 3.02083], [-65.87602, 3.0798], [-65.80764, 3.13566], [-65.72683, 3.16049], [-65.63669, 3.16669], [-65.51859, 3.12945], [-65.45332, 3.03635], [-65.40359, 2.92461], [-65.33521, 2.89667], [-65.30102, 2.84079], [-65.23886, 2.77871], [-65.20778, 2.71041], [-65.22021, 2.44028], [-65.27305, 2.28501], [-65.27305, 2.06139], [-65.28548, 2.02722], [-65.28548, 1.93404], [-65.4067, 1.84085], [-65.46886, 1.71348], [-65.53102, 1.57678], [-65.53102, 1.36861], [-65.49994, 1.26607], [-65.43467, 1.22567], [-65.50926, 1.13867], [-65.60251, 0.89006], [-65.60561, 0.4705], [-65.5994, -0.02678], [-65.65534, -0.27853], [-65.75096, -0.53515]]]}}, {"type": "Feature", "properties": {"title": "Mawakwa", "fill": "#803333", "family": "Bookkeeping", "cldf:languageReference": "mawa1268", "fill-opacity": 0.5}, "geometry": {"type": "Polygon", "coordinates": [[[-65.51574, 1.36472], [-65.52817, 1.50972], [-65.46187, 1.72099], [-65.39971, 1.8204], [-65.25881, 1.94051], [-65.26709, 2.05233], [-65.25466, 2.12688], [-65.25466, 2.25111], [-65.22151, 2.37533], [-65.19665, 2.49954], [-65.20908, 2.67755], [-65.22151, 2.75206], [-64.93971, 2.76034], [-64.67035, 2.65271], [-64.47972, 2.58234], [-64.34711, 2.47056], [-64.23522, 2.32978], [-64.18963, 2.2097], [-64.19378, 2.0192], [-64.24351, 1.89495], [-64.26423, 1.82868], [-64.23936, 1.72513], [-64.19378, 1.56772], [-64.25594, 1.4393], [-64.33053, 1.31501], [-64.50044, 1.15343], [-64.66206, 1.0457], [-64.86926, 1.01255], [-65.10962, 1.02498], [-65.30854, 1.11614], [-65.43286, 1.21557], [-65.49916, 1.28601], [-65.51574, 1.36472]]]}}, {"type": "Feature", "properties": {"title": "Piapoco", "fill": "#CC5151", "family": "Arawakan", "cldf:languageReference": "piap1246", "fill-opacity": 0.5}, "geometry": {"type": "Polygon", "coordinates": [[[-67.53764, 4.02669], [-67.65431, 4.03773], [-67.778, 4.07402], [-67.91043, 4.15821], [-68.07488, 4.21481], [-68.24223, 4.22062], [-68.40231, 4.18579], [-68.60023, 4.11176], [-68.67008, 3.98983], [-68.69336, 3.91143], [-68.68172, 3.83157], [-68.67444, 3.81596], [-68.61332, 3.77676], [-68.49545, 3.79418], [-68.38194, 3.74626], [-68.3361, 3.54366], [-68.29244, 3.4064], [-68.55002, 3.23206], [-68.9102, 3.06968], [-69.11321, 2.97158], [-69.21144, 2.88983], [-69.33913, 2.86367], [-69.59781, 2.88656], [-69.86303, 2.83424], [-70.05621, 2.71323], [-70.12825, 2.5595], [-70.12498, 2.41884], [-70.05949, 2.33705], [-69.99728, 2.22581], [-70.09551, 2.14074], [-70.23958, 2.09166], [-70.46551, 2.10147], [-70.61613, 2.24871], [-70.73073, 2.46463], [-70.70453, 4.9133], [-70.50152, 4.93939], [-70.33944, 5.0242], [-70.23467, 5.12205], [-70.13152, 5.1726], [-70.07259, 5.15303], [-70.03002, 5.08781], [-70.03493, 4.98343], [-70.11679, 4.90514], [-70.2052, 4.804], [-70.23958, 4.67837], [-70.22484, 4.56414], [-70.15936, 4.49396], [-70.03657, 4.46785], [-69.91214, 4.48254], [-69.78281, 4.57556], [-69.70586, 4.7469], [-69.67312, 4.99485], [-69.67803, 5.12205], [-69.70259, 5.33237], [-69.72059, 5.43668], [-69.69604, 5.62408], [-69.62891, 5.7316], [-69.53723, 5.80165], [-69.4652, 5.80816], [-69.35223, 5.76581], [-69.26382, 5.67459], [-69.15741, 5.52794], [-68.97405, 5.21988], [-68.88564, 5.08454], [-68.85944, 5.03399], [-68.81033, 4.95734], [-68.77431, 4.89046], [-68.72683, 4.86273], [-68.66626, 4.8611], [-68.53201, 4.90188], [-68.41905, 4.94755], [-68.22422, 4.96223], [-68.09652, 4.97038], [-67.90006, 4.96875], [-67.77728, 4.86599], [-67.54643, 4.79911], [-67.44657, 4.70284], [-67.35816, 4.53313], [-67.31523, 4.36864], [-67.28758, 4.23949], [-67.22209, 4.0987], [-67.19153, 4.03773], [-67.19456, 4.0376], [-67.19021, 4.03606], [-67.17273, 3.97793], [-67.28462, 3.98491], [-67.38135, 3.96863], [-67.53764, 4.02669]]]}}, {"type": "Feature", "properties": {"title": "Puinave", "fill": "#51CCCC", "family": null, "cldf:languageReference": "puin1248", "fill-opacity": 0.5}, "geometry": {"type": "Polygon", "coordinates": [[[-67.5697, 3.06585], [-67.66049, 3.17594], [-67.71943, 3.31324], [-67.72598, 3.41784], [-67.72598, 3.49628], [-67.77182, 3.56817], [-67.84058, 3.61066], [-67.90279, 3.63026], [-67.99447, 3.61066], [-68.07306, 3.57144], [-68.14837, 3.47013], [-68.22695, 3.44071], [-68.29571, 3.42764], [-68.32846, 3.47013], [-68.33828, 3.50281], [-68.32846, 3.627], [-68.41359, 3.76423], [-68.46925, 3.80344], [-68.56421, 3.77077], [-68.67226, 3.80997], [-68.70173, 3.93738], [-68.63952, 4.03864], [-68.51509, 4.15295], [-68.38412, 4.19214], [-68.20403, 4.20846], [-68.12545, 4.22479], [-67.965, 4.1954], [-67.8766, 4.14315], [-67.80784, 4.0713], [-67.68341, 4.04844], [-67.53934, 4.01578], [-67.39854, 3.97658], [-67.32651, 3.84918], [-67.26757, 3.66948], [-67.24465, 3.49301], [-67.22828, 3.38515], [-67.28067, 3.28055], [-67.35925, 3.17594], [-67.36349, 3.17307], [-67.3831, 3.13631], [-67.48509, 3.04611], [-67.49208, 2.97977], [-67.54569, 3.00945], [-67.5697, 3.06585]]]}}, {"type": "Feature", "properties": {"title": "Yavitero-Pareni", "fill": "#CC5151", "family": "Arawakan", "cldf:languageReference": "yavi1244", "fill-opacity": 0.5}, "geometry": {"type": "Polygon", "coordinates": [[[-67.2205, 0.95997], [-67.27453, 1.06801], [-67.31136, 1.2497], [-67.29663, 1.41664], [-67.32119, 1.57376], [-67.39977, 1.66459], [-67.54712, 1.81432], [-67.65271, 1.95667], [-67.66008, 2.07938], [-67.57904, 2.26098], [-67.52502, 2.38857], [-67.51274, 2.5137], [-67.53729, 2.61919], [-67.58395, 2.71732], [-67.57167, 2.82034], [-67.46608, 2.93807], [-67.38013, 2.94788], [-67.27698, 2.85713], [-67.20577, 2.7026], [-67.19594, 2.59957], [-67.1542, 2.50389], [-67.16156, 2.35177], [-67.16893, 1.96404], [-67.13946, 1.73823], [-67.06088, 1.55412], [-67.04369, 1.33808], [-67.08544, 1.16377], [-67.16402, 1.02381], [-67.2205, 0.95997]]]}}], "properties": {"title": "Speaker areas for languages", "description": "Speaker areas aggregated for Glottolog language-level languoids, color-coded by family."}} \ No newline at end of file diff --git a/tests/fixtures/dataset/media.csv b/tests/fixtures/dataset/media.csv new file mode 100644 index 0000000..5538fc5 --- /dev/null +++ b/tests/fixtures/dataset/media.csv @@ -0,0 +1,2 @@ +ID,Name,Description,Media_Type,Download_URL,Path_In_Zip +languages,Speaker areas for languages,"Speaker areas aggregated for Glottolog language-level languoids, color-coded by family.",application/geo+json,languages.geojson, diff --git a/tests/fixtures/dataset/sources.bib b/tests/fixtures/dataset/sources.bib new file mode 100644 index 0000000..91b206b --- /dev/null +++ b/tests/fixtures/dataset/sources.bib @@ -0,0 +1,10 @@ +@book{zucchi2017arqueologia, + author = {Zucchi, Alberta}, + address = {Caracas}, + isbn = {978-980-419-011-7}, + publisher = {Centro Nacional de Estudios Históricos}, + series = {Collección clásicos de la arqueología Venezolana}, + title = {Arqueología de los llanos occidentales y el Orinoco}, + url = {https://docplayer.es/109862754-Arqueologia-de-los-llanos-occidentales-y-el-orinoco.html}, + year = {2017} +} diff --git a/tests/fixtures/glottolog/languoids/glottocodes.json b/tests/fixtures/glottolog/languoids/glottocodes.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/tests/fixtures/glottolog/languoids/glottocodes.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/tests/fixtures/glottolog/languoids/tree/abcd1234/abcd1235/abcd1236/md.ini b/tests/fixtures/glottolog/languoids/tree/abcd1234/abcd1235/abcd1236/md.ini new file mode 100644 index 0000000..e69952a --- /dev/null +++ b/tests/fixtures/glottolog/languoids/tree/abcd1234/abcd1235/abcd1236/md.ini @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +[core] +name = dialect +level = dialect +macroareas = + Eurasia +countries = + RU + Turkey (TR) +status = Definitely endangered + +[sources] +glottolog = + **a:key** + +[triggers] +lgcode = + dialect + +[endangerment] +source = **a:key**:234 +status = threatened +date = 2019-01-01 +comment = \ No newline at end of file diff --git a/tests/fixtures/glottolog/languoids/tree/abcd1234/abcd1235/md.ini b/tests/fixtures/glottolog/languoids/tree/abcd1234/abcd1235/md.ini new file mode 100644 index 0000000..d98bf02 --- /dev/null +++ b/tests/fixtures/glottolog/languoids/tree/abcd1234/abcd1235/md.ini @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +[core] +name = language +level = language +longitude = -68.81829931230445 +latitude = 0.9985214549446771 +macroareas = + Eurasia + Australia +hid = abc +iso639-3 = abc + +[triggers] +lgcode = + language + lang AND NOT dial + +inlg = + language + +[iso_retirement] +code = c +comment = c +change_to = xyz +name = c +effective = c + +[endangerment] +source = ElCat +comment = nope +status = sleeping +date = 2019-01-01 diff --git a/tests/fixtures/glottolog/languoids/tree/abcd1234/abcd1237/md.ini b/tests/fixtures/glottolog/languoids/tree/abcd1234/abcd1237/md.ini new file mode 100644 index 0000000..8e80a8e --- /dev/null +++ b/tests/fixtures/glottolog/languoids/tree/abcd1234/abcd1237/md.ini @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +[core] +name = language2 +level = language +latitude = 1.5 +longitude = -20 +macroareas = + Eurasia diff --git a/tests/fixtures/glottolog/languoids/tree/abcd1234/md.ini b/tests/fixtures/glottolog/languoids/tree/abcd1234/md.ini new file mode 100644 index 0000000..11c6e6c --- /dev/null +++ b/tests/fixtures/glottolog/languoids/tree/abcd1234/md.ini @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +[core] +name = family +level = family +hid = NOCODE_Family-name +iso639-3 = aaa + +[classification] +sub = **hh:s:Karang:Tati-Harzani** +familyrefs = **hh:s:Karang:Tati-Har** diff --git a/tests/fixtures/glottolog/languoids/tree/book1242/book1243/md.ini b/tests/fixtures/glottolog/languoids/tree/book1242/book1243/md.ini new file mode 100644 index 0000000..b592501 --- /dev/null +++ b/tests/fixtures/glottolog/languoids/tree/book1242/book1243/md.ini @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +[core] +name = booked +level = language + +[hh_ethnologue_comment] +isohid = abc +comment_type = missing +ethnologue_versions = E16 +comment = none \ No newline at end of file diff --git a/tests/fixtures/glottolog/languoids/tree/book1242/md.ini b/tests/fixtures/glottolog/languoids/tree/book1242/md.ini new file mode 100644 index 0000000..6e1e9da --- /dev/null +++ b/tests/fixtures/glottolog/languoids/tree/book1242/md.ini @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +[core] +name = Bookkeeping +level = family \ No newline at end of file diff --git a/tests/fixtures/glottolog/languoids/tree/isol1234/dial1234/md.ini b/tests/fixtures/glottolog/languoids/tree/isol1234/dial1234/md.ini new file mode 100644 index 0000000..b304074 --- /dev/null +++ b/tests/fixtures/glottolog/languoids/tree/isol1234/dial1234/md.ini @@ -0,0 +1,9 @@ +# -*- coding: utf-8 -*- +[core] +name = isolate (dialect) +level = dialect +latitude = 100 +longitude = -200 + +[sources] +glottolog = **abc:xyz** \ No newline at end of file diff --git a/tests/fixtures/glottolog/languoids/tree/isol1234/md.ini b/tests/fixtures/glottolog/languoids/tree/isol1234/md.ini new file mode 100644 index 0000000..122b4e5 --- /dev/null +++ b/tests/fixtures/glottolog/languoids/tree/isol1234/md.ini @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +[core] +name = isolate +level = language \ No newline at end of file diff --git a/tests/fixtures/glottolog/references/BIBFILES.ini b/tests/fixtures/glottolog/references/BIBFILES.ini new file mode 100644 index 0000000..02a2c87 --- /dev/null +++ b/tests/fixtures/glottolog/references/BIBFILES.ini @@ -0,0 +1,30 @@ +[DEFAULT] +encoding = utf-8 +normalize = NFC +sortkey = bibkey +priority = 0 + +[a.bib] +name = A +title = B +description = A. +abbr = a +priority = -10 + +[hh.bib] +name = HH +title = HH +description = H. +abbr = h + +[iso6393.bib] +name = iso +title = iso +description = iso +abbr = iso + +[b.bib] +name = B +title = B +description = B. +abbr = b diff --git a/tests/fixtures/glottolog/references/bibtex/a.bib b/tests/fixtures/glottolog/references/bibtex/a.bib new file mode 100644 index 0000000..085555c --- /dev/null +++ b/tests/fixtures/glottolog/references/bibtex/a.bib @@ -0,0 +1,27 @@ +@book{s:Andalusi:Turk, + author = {'Ab\=u \textsubdot\textsuperscript{c}{H}ayy\=an al-'Andalus\=i}, + title = {Kit\=ab al-'idr\=ak li-lis\=an al-'atr\=ak}, + publisher = {Istanbul: Beyazit National Library}, + pages = {132}, + year = {1313}, + glottolog_ref_id = {319108}, + hhtype = {grammar_sketch}, + lgcode = {Mixture of Oguz and Qipchaq close to Western Qipchaq esp Crimean Tatar = Crimean Tatar [crh]}, + macro_area = {Eurasia} +} +@book{s:Karang:Tati-Harzani, + author = {'Abd-al-'Ali Karang}, + title = {Tati va Harzani}, + publisher = {Tabriz: Tabriz University Press}, + address = {Tabriz}, + pages = {6+160}, + year = {1334 [1953]}, + glottolog_ref_id = {41998}, + hhtype = {grammar_sketch}, + lgcode = {Harzani [hrz]}, + macro_area = {Eurasia} +} +@misc{key, + author = {Some One}, + lgcode = {abc} +} diff --git a/tests/fixtures/glottolog/references/bibtex/b.bib b/tests/fixtures/glottolog/references/bibtex/b.bib new file mode 100644 index 0000000..941188a --- /dev/null +++ b/tests/fixtures/glottolog/references/bibtex/b.bib @@ -0,0 +1,12 @@ +@article{arakawa97, + author = {Arakawa, Shintaro}, + title = {\zh{西夏語通韻字典} {S}eikago tsūin jiten}, + journal = {\zh{言語学研究} Gengogaku Kenkyū}, + volume = {16}, + pages = {1-153}, + year = {1997}, + glottolog_ref_id = {319108}, + note = {(\zh{荒川新太郎})}, + owner = {向柏霖}, + timestamp = {2009.08.10} +} diff --git a/tests/fixtures/glottolog/references/bibtex/hh.bib b/tests/fixtures/glottolog/references/bibtex/hh.bib new file mode 100644 index 0000000..8acc30c --- /dev/null +++ b/tests/fixtures/glottolog/references/bibtex/hh.bib @@ -0,0 +1,23 @@ +@book{s:Karang:Tati-Harzani, + author = {'Abd-al-'Ali Karang}, + title = {Tati va Harzani}, + publisher = {Tabriz: Tabriz University Press}, + address = {Tabriz}, + pages = {6+160}, + year = {1334 [1953]}, + glottolog_ref_id = {41999}, + hhtype = {grammar_sketch}, + lgcode = {Harzani [hrz], [NOCODE_Family]}, + macro_area = {Eurasia} +} +@misc{hel:Campbell:ElCat, + author = {Campbell, Lyle and Lee, Nala Huiying and Okura, Eve and Simpson, Sean and Ueki, Kaori}, + title = {The Catalogue of Endangered Languages (ElCat)}, + year = {2017}, + hhtype = {overview;socling}, + lgcode = {aaa}, + glottolog_ref_id = {1}, + howpublished = {Database available at http://endangeredlanguages.com/userquery/download/, accessed 2017-07-27.}, + inlg = {English [eng]}, + macro_area = {Eurasia} +} diff --git a/tests/fixtures/glottolog/references/bibtex/iso6393.bib b/tests/fixtures/glottolog/references/bibtex/iso6393.bib new file mode 100644 index 0000000..d743d96 --- /dev/null +++ b/tests/fixtures/glottolog/references/bibtex/iso6393.bib @@ -0,0 +1,5 @@ + +@misc{2006-001, + author = {none}, + glottolog_ref_id = {12} +} diff --git a/tests/test_cli.py b/tests/test_cli.py index 71381bd..0ad9c2e 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,6 +1,15 @@ from cldfbench.__main__ import main +def test_glottolog_distance(fixtures_dir, capsys): + main([ + 'geojson.glottolog_distance', + str(fixtures_dir / 'dataset'), + '--glottolog', str(fixtures_dir / 'glottolog')]) + out, _ = capsys.readouterr() + assert 'curr1243' in out + + def test_webmercator(fixtures_dir, tmp_path): o = tmp_path / 'web.tif' main(['geojson.webmercator', str(fixtures_dir / 'geo.tif'), str(o)]) diff --git a/tests/test_create.py b/tests/test_create.py index ab7ed48..45234d8 100644 --- a/tests/test_create.py +++ b/tests/test_create.py @@ -26,7 +26,7 @@ def test_correct_longitude(in_, out_): assert correct_longitude(in_) == out_ -def test_fixed_geometry(): +def test_fixed_geometry(recwarn): f = { "type": "Feature", "properties": {}, diff --git a/tests/test_geojson.py b/tests/test_geojson.py index 07d398e..c69e807 100644 --- a/tests/test_geojson.py +++ b/tests/test_geojson.py @@ -1,5 +1,10 @@ +import json +import decimal + import pytest +from numpy.ma.testutils import approx from shapely.geometry import shape +from clldutils.jsonlib import load from cldfgeojson.geojson import * @@ -17,3 +22,20 @@ ) def test_pacific_centered(type_, coords, check): assert check(shape(pacific_centered(dict(type=type_, coordinates=coords)))) + + +def test_dumps(tmp_path): + with pytest.raises(TypeError): + dumps(decimal.Decimal('1')) + + c = 1.23456789 + assert '1.2345678' in json.dumps(c) + obj = json.loads(dumps({'properties': {'a': c}, 'coordinates': [[c], c]})) + assert approx(obj['properties']['a'], c) + assert approx(obj['coordinates'][0][0], 1.23456) + + p = tmp_path / 'test.geojson' + dump({'properties': {'a': c}, 'coordinates': [[c], c]}, p) + obj = load(p) + assert approx(obj['properties']['a'], c) + assert approx(obj['coordinates'][0][0], 1.23456)