diff --git a/.github/workflows/jekyll.yml b/.github/workflows/jekyll.yml
index 0a467aa..514cf82 100644
--- a/.github/workflows/jekyll.yml
+++ b/.github/workflows/jekyll.yml
@@ -32,7 +32,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
@@ -48,7 +48,7 @@ jobs:
JEKYLL_ENV: production
- name: Upload artifact
# Automatically uploads an artifact from the './_site' directory by default
- uses: actions/upload-pages-artifact@v3
+ uses: actions/upload-pages-artifact@v4
# Deployment job
deploy:
diff --git a/.github/workflows/validate-profile-and-schemas.yml b/.github/workflows/validate-profile-and-schemas.yml
index 707afd3..799dd7a 100644
--- a/.github/workflows/validate-profile-and-schemas.yml
+++ b/.github/workflows/validate-profile-and-schemas.yml
@@ -10,9 +10,9 @@ jobs:
validate-profile-and-schemas:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6
- name: Set up Python 3.9
- uses: actions/setup-python@v5
+ uses: actions/setup-python@v6
with:
python-version: 3.9
- name: Install dependencies
diff --git a/CITATION.cff b/CITATION.cff
index d4fc194..b720e1f 100644
--- a/CITATION.cff
+++ b/CITATION.cff
@@ -1,5 +1,4 @@
cff-version: 1.2.0
-message: 'To cite "GeoLocator DP" in publications use:'
type: software
license: MIT
title: GeoLocator Data Package
@@ -9,7 +8,17 @@ authors:
email: rafnuss@gmail.com
affiliation: Swiss Ornithological Institute
orcid: https://orcid.org/0000-0002-8185-1020
+ - family-names: Capilla-Lasheras
+ given-names: Pablo
+ email: pablo.capilla@gvogelwarte.ch
+ affiliation: Swiss Ornithological Institute
+ orcid: https://orcid.org/0000-0001-6091-7089
+ - family-names: Desmet
+ given-names: Peter
+ email: peter.desmet@inbo.be
+ affiliation: Research Institute for Nature and Forest
+ orcid: https://orcid.org/0000-0002-8442-8025
repository-code: https://github.com/rafnuss/geolocator-dp
-url: https://raphaelnussbaumer.com/GeoLocator-DP/
+url: https://geopressure.org/GeoLocator-DP/
date-released: "2024-12-02"
doi: 10.5281/zenodo.14258411
diff --git a/README.md b/README.md
index 79a9f17..83c41b8 100644
--- a/README.md
+++ b/README.md
@@ -1,94 +1,46 @@
----
-title: GeoLocator DP
-background: /assets/home.png
-permalink: /
-description: Data exchange format for geolocator data
----
+# GeoLocator DP
-**GeoLocator Data Package** (GeoLocator DP) is a data exchange format for geolocator data. It follows the [Data Package standard](https://datapackage.org/standard/data-package/) for structuring the data.
+GeoLocator DP is a Data Package profile for geolocator data (raw measurements, field observations, and optional GeoPressureR trajectory outputs).
-## Structure
+## Documentation
-A GeoLocator Data Package is organized into three components: (1) the project metadata, (2) the core resources containing the main dataset, and (3) optional trajectory data generated with the [GeoPressure suite](https://raphaelnussbaumer.com/GeoPressureManual/#the-geopressure-suite).
+- Website: https://geopressure.org/GeoLocator-DP/
+- GeoLocator Manual: https://raphaelnussbaumer.com/GeoPressureManual/geolocator-intro.html
+- GeoLocatoR package: https://raphaelnussbaumer.com/GeoLocatoR/
-### 1. Metadata
+## Repository Contents
-The description of the project and the data is contained in [`datapackage.json`](https://raphaelnussbaumer.com/GeoLocator-DP/datapackage/).
+- `geolocator-dp-profile.json`: GeoLocator DP package profile
+- `*-table-schema.json`: table schemas for core and GeoPressureR resources
+- `pages/`: website pages rendered by Jekyll
+- `example/`: example CSV resources
+- `tests/`: validation tests
-| File | Description |
-| ------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| [`datapackage.json`](https://raphaelnussbaumer.com/GeoLocator-DP/datapackage/) | List of the project's metadata, such as the package's title, licenses, contributors, etc., as well as a list of the data [`resources`](https://datapackage.org/standard/data-resource/) that make up the package |
+## Local Development
-### 2. Core Resources
+Install Ruby dependencies:
-The core GeoLocator DP resources consist of the raw geolocator data. These `resources` can be generated without any analysis of the geolocator data.
+```bash
+bundle install
+```
-| File | Description |
-| ------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------- |
-| [`tags.csv`](https://raphaelnussbaumer.com/GeoLocator-DP/core/tags/) | Table of devices used in the study. We assume that a `tag` is only used once on a single animal. |
-| [`measurements.csv`](https://raphaelnussbaumer.com/GeoLocator-DP/core/measurements/) | Table with the raw measurements of all sensors (e.g., light, pressure, ...) for all tags. |
-| [`observations.csv`](https://raphaelnussbaumer.com/GeoLocator-DP/core/observations/) | Table with the field observations associated with tags such as equipment, retrieval, or other events. |
+Run the website locally with live reload:
-### 3. GeoPressureR Resources
+```bash
+bundle exec jekyll serve --livereload --incremental
+```
-The GeoPressureR extension consists of optional trajectory data generated through the [GeoPressureR workflow analysis](https://raphaelnussbaumer.com/GeoPressureManual/geopressuretemplate-workflow.html).
+Create a production-style build:
-| File | Description |
-| --------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
-| [`staps.csv`](https://raphaelnussbaumer.com/GeoLocator-DP/geopressurer/staps) | Table of the stationary periods of all tags. |
-| [`paths.csv`](https://raphaelnussbaumer.com/GeoLocator-DP/geopressurer/paths) | Table of the trajectory of all tags, typically most likely path or simulation paths. |
-| [`edges.csv`](https://raphaelnussbaumer.com/GeoLocator-DP/geopressurer/edges) | Table containing the flight information of the edges associated with the paths. |
-| [`twilights.csv`](https://raphaelnussbaumer.com/GeoLocator-DP/geopressurer/twilights) | Table of the twilights estimated from light data for all tags. |
-| [`pressurepaths.csv`](https://raphaelnussbaumer.com/GeoLocator-DP/geopressurer/pressurepaths) | Table of pressure-based paths. |
+```bash
+JEKYLL_ENV=production bundle exec jekyll build
+```
-## Where to find and explore GeoLocator Data Packages
+Run validation tests:
-
- Explore the most likely trajectories of all existing data packages on a 3D map with GeoLocatorExplorer.
-
-
-
-
-## Ecosystem
-
-
-
-
-
-
-
- The Geolocator Manual R book has a dedicated part on the use of the GeoLocator Data Package. This is a great place to start learning more about how to use it with your GeoPressureTemplate project.
-
-
-
-
-
-
-
- The GeoLocatoR R package is designed to handle GeoLocator DP: creating a DP, adding resources, writing a DP, and reading a DP. It is essentially an extension of the frictionlessr package for geolocator data.
-
-
-
-
-
- GeoPressureR is the main package to analyze geolocator data. Once a GeoLocator Data Package is created, GeoPressureR is our recommended software to read the data into R and analyze the data.
-
+
diff --git a/_sass/_custom.scss b/_sass/_custom.scss
new file mode 100644
index 0000000..e66b9f9
--- /dev/null
+++ b/_sass/_custom.scss
@@ -0,0 +1,86 @@
+// Alert palette overrides to align Bootstrap callouts with GeoLocator DP branding.
+
+.alert {
+ border-left-width: 0.35rem;
+ padding-left: 2.75rem !important;
+ position: relative;
+}
+
+.alert::before {
+ content: "";
+ position: absolute;
+ left: 0.8rem;
+ top: calc(var(--bs-alert-padding-y) + 0.35rem);
+ width: 1rem;
+ height: 1rem;
+ background-color: currentColor;
+ -webkit-mask-repeat: no-repeat;
+ mask-repeat: no-repeat;
+ -webkit-mask-size: contain;
+ mask-size: contain;
+}
+
+.alert-primary {
+ --bs-alert-color: #1f3a34;
+ --bs-alert-bg: #e7f2ee;
+ --bs-alert-border-color: #b6d0c6;
+ --bs-alert-link-color: #173029;
+ border-left-color: #516f6a;
+}
+
+.alert-primary::before {
+ -webkit-mask-image: url("../../icons/check-circle-fill.svg");
+ mask-image: url("../../icons/check-circle-fill.svg");
+}
+
+.alert-info {
+ --bs-alert-color: #0f4550;
+ --bs-alert-bg: #e6f4f7;
+ --bs-alert-border-color: #b8d9e1;
+ --bs-alert-link-color: #0b3942;
+ border-left-color: #3c8aa0;
+}
+
+.alert-info::before {
+ -webkit-mask-image: url("../../icons/info-circle-fill.svg");
+ mask-image: url("../../icons/info-circle-fill.svg");
+}
+
+.alert-tips {
+ --bs-alert-color: #3f3307;
+ --bs-alert-bg: #fff8e8;
+ --bs-alert-border-color: #ecd8a3;
+ --bs-alert-link-color: #2f2505;
+ border-left-color: #bf8b12;
+}
+
+.alert-tips::before {
+ -webkit-mask-image: url("../../icons/info-circle-fill.svg");
+ mask-image: url("../../icons/info-circle-fill.svg");
+}
+
+.alert-warning {
+ --bs-alert-color: #5f460f;
+ --bs-alert-bg: #fff6df;
+ --bs-alert-border-color: #f0da9c;
+ --bs-alert-link-color: #4a380b;
+ border-left-color: #c9951b;
+}
+
+.alert-warning::before {
+ -webkit-mask-image: url("../../icons/exclamation-triangle-fill.svg");
+ mask-image: url("../../icons/exclamation-triangle-fill.svg");
+}
+
+.alert-danger {
+ --bs-alert-color: #6d1f23;
+ --bs-alert-bg: #fbeaea;
+ --bs-alert-border-color: #f2c7c9;
+ --bs-alert-link-color: #5a171b;
+ border-left-color: #c1353f;
+}
+
+.alert-danger::before {
+ -webkit-mask-image: url("../../icons/exclamation-triangle-fill.svg");
+ mask-image: url("../../icons/exclamation-triangle-fill.svg");
+}
diff --git a/assets/curation.jpg b/assets/curation.jpg
new file mode 100644
index 0000000..74dd428
Binary files /dev/null and b/assets/curation.jpg differ
diff --git a/assets/edges.jpg b/assets/edges.jpg
new file mode 100644
index 0000000..9e6f005
Binary files /dev/null and b/assets/edges.jpg differ
diff --git a/assets/icons/bezier2.svg b/assets/icons/bezier2.svg
new file mode 100644
index 0000000..8a59238
--- /dev/null
+++ b/assets/icons/bezier2.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/assets/icons/binoculars-fill.svg b/assets/icons/binoculars-fill.svg
new file mode 100644
index 0000000..d6d6dc0
--- /dev/null
+++ b/assets/icons/binoculars-fill.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/assets/icons/check-circle-fill.svg b/assets/icons/check-circle-fill.svg
new file mode 100644
index 0000000..0b7f412
--- /dev/null
+++ b/assets/icons/check-circle-fill.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/assets/icons/cpu-fill.svg b/assets/icons/cpu-fill.svg
new file mode 100644
index 0000000..ce6e294
--- /dev/null
+++ b/assets/icons/cpu-fill.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/assets/icons/exclamation-triangle-fill.svg b/assets/icons/exclamation-triangle-fill.svg
new file mode 100644
index 0000000..52fd508
--- /dev/null
+++ b/assets/icons/exclamation-triangle-fill.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/assets/icons/info-circle-fill.svg b/assets/icons/info-circle-fill.svg
new file mode 100644
index 0000000..d2e382b
--- /dev/null
+++ b/assets/icons/info-circle-fill.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/assets/icons/key-fill.svg b/assets/icons/key-fill.svg
new file mode 100644
index 0000000..fdab8d6
--- /dev/null
+++ b/assets/icons/key-fill.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/assets/icons/pin-map-fill.svg b/assets/icons/pin-map-fill.svg
new file mode 100644
index 0000000..9db0d29
--- /dev/null
+++ b/assets/icons/pin-map-fill.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/assets/icons/signpost-split.svg b/assets/icons/signpost-split.svg
new file mode 100644
index 0000000..7fb69b7
--- /dev/null
+++ b/assets/icons/signpost-split.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/assets/icons/speedometer2.svg b/assets/icons/speedometer2.svg
new file mode 100644
index 0000000..75e79c8
--- /dev/null
+++ b/assets/icons/speedometer2.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/assets/icons/sunrise-fill.svg b/assets/icons/sunrise-fill.svg
new file mode 100644
index 0000000..c922d7c
--- /dev/null
+++ b/assets/icons/sunrise-fill.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/assets/icons/wind.svg b/assets/icons/wind.svg
new file mode 100644
index 0000000..2ac05cd
--- /dev/null
+++ b/assets/icons/wind.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/assets/paths.jpg b/assets/paths.jpg
new file mode 100644
index 0000000..96fbc6b
Binary files /dev/null and b/assets/paths.jpg differ
diff --git a/assets/pressurepaths.jpg b/assets/pressurepaths.jpg
new file mode 100644
index 0000000..f76b690
Binary files /dev/null and b/assets/pressurepaths.jpg differ
diff --git a/assets/schema-overview.jpg b/assets/schema-overview.jpg
new file mode 100644
index 0000000..39adc76
Binary files /dev/null and b/assets/schema-overview.jpg differ
diff --git a/assets/staps.jpg b/assets/staps.jpg
new file mode 100644
index 0000000..4fd4f05
Binary files /dev/null and b/assets/staps.jpg differ
diff --git a/assets/twilights.jpg b/assets/twilights.jpg
new file mode 100644
index 0000000..0418e55
Binary files /dev/null and b/assets/twilights.jpg differ
diff --git a/assets/user_steps.svg b/assets/user_steps.svg
new file mode 100644
index 0000000..68560c5
--- /dev/null
+++ b/assets/user_steps.svg
@@ -0,0 +1,1162 @@
+
+
\ No newline at end of file
diff --git a/edges-table-schema.json b/edges-table-schema.json
index 43f6e27..5e672e6 100644
--- a/edges-table-schema.json
+++ b/edges-table-schema.json
@@ -1,7 +1,7 @@
{
"name": "edges",
"title": "Edges",
- "description": "In GeoPressureR, we uses `edges` (of a graph; See more information on the movement model in the [GeoPressureManual](https://raphaelnussbaumer.com/GeoPressureManual/trajectory.html)) to extract flight information from GeoPressureP [`paths`](geopressurer/paths) using path2edge().",
+ "description": "In GeoPressureR, `edges` (graph edges; see more information on the movement model in the [GeoPressureManual](https://raphaelnussbaumer.com/GeoPressureManual/trajectory.html)) are used to extract flight information from GeoPressureR [`paths`](/GeoLocator-DP/geopressurer/paths) using `path2edge()`.",
"$schema": "https://datapackage.org/profiles/2.0/tableschema.json",
"fields": [
{
@@ -25,7 +25,7 @@
},
{
"name": "stap_s",
- "description": "Identifier of the SOURCE stationary period. Foreign key to [`staps.stap_id`](/GeoLocator-DP/geopressurer/staps#stap_id)",
+ "description": "Identifier of the SOURCE stationary period. Together with [`tag_id`](#tag_id), this forms a foreign key to [`staps`](/GeoLocator-DP/geopressurer/staps) (`tag_id`, `stap_id`).",
"type": "number",
"constraints": {
"required": true
@@ -34,7 +34,7 @@
},
{
"name": "stap_t",
- "description": "Identifier of the TARGET stationary period. Generally `stap_s+1` except if `include=FALSE` for intermediate stap_id. Foreign key to [`staps.stap_id`](/GeoLocator-DP/geopressurer/staps#stap_id).",
+ "description": "Identifier of the TARGET stationary period. Generally `stap_s+1`, except if `include=FALSE` for intermediate `stap_id` values. Together with [`tag_id`](#tag_id), this forms a foreign key to [`staps`](/GeoLocator-DP/geopressurer/staps) (`tag_id`, `stap_id`).",
"type": "number",
"constraints": {
"required": true
@@ -43,7 +43,7 @@
},
{
"name": "lat_s",
- "description": "Latitude of source the stationary period.",
+ "description": "Latitude of the source stationary period.",
"type": "number",
"constraints": {
"required": true,
@@ -89,29 +89,9 @@
"example": "23.84995",
"skos:exactMatch": "http://rs.tdwg.org/dwc/terms/decimalLongitude"
},
- {
- "name": "s",
- "description": "Index of the 2D coordinate of the source stap. See [`paths.ind`](geopressurer/paths#ind) for more information",
- "type": "integer",
- "constraints": {
- "required": false,
- "minimum": 1
- },
- "example": "23343"
- },
- {
- "name": "t",
- "description": "Index of the 2D coordinate of the target stap. See [`paths.ind`](geopressurer/paths#ind) for more information",
- "type": "integer",
- "constraints": {
- "required": false,
- "minimum": 1
- },
- "example": "23343"
- },
{
"name": "j",
- "description": "Same as [`paths.j`](geopressurer/paths#j). Unique identifier for each trajectory. Only useful for `edges.type='simulation'`. Integer from `1` to `nj` as defined in [`GeoPressureR::graph_simulation()`](https://raphaelnussbaumer.com/GeoPressureR/reference/graph_simulation)`.",
+ "description": "Same as [`paths.j`](/GeoLocator-DP/geopressurer/paths#j). Unique identifier for each trajectory. Only useful for `edges.type='simulation'`. Integer from `1` to `nj` as defined in [`GeoPressureR::graph_simulation()`](https://raphaelnussbaumer.com/GeoPressureR/reference/graph_simulation).",
"type": "integer",
"constraints": {
"required": false,
@@ -141,7 +121,7 @@
},
{
"name": "n",
- "description": "Number of flight.",
+ "description": "Flight number.",
"type": "integer",
"constraints": {
"required": false,
@@ -151,7 +131,7 @@
},
{
"name": "distance",
- "description": "distance of the flight in km.",
+ "description": "Distance of the flight in km.",
"type": "number",
"constraints": {
"required": false,
@@ -162,7 +142,7 @@
},
{
"name": "bearing",
- "description": "Direction of the flight in degree. 0 indicates north, clockwise. In general should be 0°-365°, but also allows -180° to 180°.",
+ "description": "Direction of the flight in degrees. 0 indicates north and values increase clockwise. In general, this should be 0°-360°, but -180° to 180° is also allowed.",
"type": "number",
"constraints": {
"required": false,
@@ -223,17 +203,17 @@
}
},
{
- "fields": "stap_s",
+ "fields": ["tag_id", "stap_s"],
"reference": {
"resource": "staps",
- "fields": "stap_id"
+ "fields": ["tag_id", "stap_id"]
}
},
{
- "fields": "stap_t",
+ "fields": ["tag_id", "stap_t"],
"reference": {
"resource": "staps",
- "fields": "stap_id"
+ "fields": ["tag_id", "stap_id"]
}
}
],
diff --git a/geolocator-dp-profile.json b/geolocator-dp-profile.json
index 31c67ca..ca34a66 100644
--- a/geolocator-dp-profile.json
+++ b/geolocator-dp-profile.json
@@ -3,532 +3,26 @@
"title": "Geolocator Data Package",
"description": "Data exchange format for geolocator data.",
"type": "object",
- "$defs": {
- "version": {
- "type": "string",
- "pattern": "^0\\.3\\.1$"
- },
- "taxonomicName": {
- "type": "string",
- "description": "Scientific name",
- "skos:relatedMatch": [
- "https://vocab.nerc.ac.uk/collection/MVB/current/MVB000024",
- "http://rs.tdwg.org/dwc/terms/scientificName"
- ]
- },
- "contributorRole": {
- "type": "string",
- "enum": [
- "ContactPerson",
- "ProjectLeader",
- "DataCollector",
- "DataCurator",
- "Researcher",
- "RightsHolder",
- "Supervisor",
- "Other"
- ]
- }
- },
"allOf": [
{
"$ref": "https://datapackage.org/profiles/2.0/datapackage.json"
},
{
- "required": [
- "$schema",
- "title",
- "created",
- "contributors",
- "licenses",
- "spatial",
- "temporal",
- "taxonomic",
- "numberTags",
- "resources"
- ],
+ "required": ["$schema", "resources"],
"properties": {
- "title": {
- "title": "Title",
- "description": "A string providing a title or one sentence description for this package. It should be plain text (no markup), capitalised like a title, NOT end in a period and less than 65 characters. See [Data Package specification](https://datapackage.org/standard/data-package/#title) and [Datacite metadata schema](https://datacite-metadata-schema.readthedocs.io/en/4.6/properties/title/).",
- "type": "string",
- "examples": ["{\n \"title\": \"Woodland Kingfisher Geolocator data\"\n}\n"],
- "skos:exactMatch": "https://vocab.nerc.ac.uk/collection/MVB/current/MVB000172"
- },
- "contributors": {
- "title": "Contributors",
- "description": "A list of contributors, where each contributor is a list with properties including at least `title` but also optionally `givenName`, `familyName`, `path`, `email`, `roles`, and `organization`. See [Data Package specification](https://datapackage.org/standard/data-package/#contributors). ",
- "type": "array",
- "minItems": 1,
- "items": {
- "properties": {
- "title": {
- "title": "Title",
- "description": "Name of the contributor.",
- "type": "string"
- },
- "givenName": {
- "type": "string",
- "description": "Given name of the contributor"
- },
- "familyName": {
- "type": "string",
- "description": "Family name of the contributor"
- },
- "path": {
- "title": "Path",
- "description": "A fully qualified URL pointing to a relevant location online for the contributor",
- "type": "string",
- "pattern": "^((?=[^./~])(?!file:)((?!\\/\\.\\.\\/)(?!\\\\)(?!:\\/\\/).)*|(http|ftp)s?:\\/\\/.*)$"
- },
- "email": {
- "title": "Email",
- "description": "An email address.",
- "type": "string",
- "format": "email",
- "examples": ["{\n \"email\": \"example@example.com\"\n}\n"]
- },
- "roles": {
- "description": "The type of contribution made by the person/organization following a subset of [DataCite Metadata Schema's contributorType](https://datacite-metadata-schema.readthedocs.io/en/4.6/appendices/appendix-1/contributorType/). We strongly suggest having `ContactPerson` and `ProjectLeader` to match Movebank requirements for a [contact person](https://vocab.nerc.ac.uk/collection/MVB/current/MVB000072/) and a [principal investigator](https://vocab.nerc.ac.uk/collection/MVB/current/MVB000164/). Any contributors should be authors of the datapackage and appear in `bibliographicCitation`. \n - `ContactPerson`: Person to whom to ask any questions related to the geolocator data package such as how to access, use, cite, any additional information. \n - `ProjectLeader`: Person officially designated as head of project (i.e., principal investigator).\n - `DataCurator`: Person in charge of building the geolocator data package, including the gathering and standardizing the metadata and maintaining data and software code. Typically the person that used the GeoLocatoR package to build the data package.\n - `Researcher`: A person involved in analyzing data or the results of the geolocator data. Typically used for the persons that run the GeoPressure analysis to produce the tracks.\n - `RightsHolder`: Person or institution owning or managing property rights, including intellectual property rights over the resource. \n - `Supervisor`: Designated administrator over the project, including funding acquisition. \n - `DataCollector`: Person responsible for finding gathering/collecting the geolocator data. Typically used for ringers and field assistants. \n - `Other`: Any person or institution making a significant contribution to the development and/or maintenance of the datapackage. Avoid using this.",
- "oneOf": [
- {
- "type": "array",
- "minItems": 1,
- "items": {
- "$ref": "#/$defs/contributorRole"
- }
- },
- {
- "$ref": "#/$defs/contributorRole"
- }
- ]
- },
- "organization": {
- "title": "Organization",
- "description": "An organizational affiliation for this contributor.",
- "type": "string"
- }
- }
- },
- "examples": [
- "{\n \"contributors\": [\n {\n \"title\": \"Yann Rime\",\n \"email\": \"yann.rime@vogelwarte.ch\",\n \"roles\": [\"Researcher\"]\n },\n {\n \"title\": \"Raphaël Nussbaumer\",\n \"email\": \"raphael.nussbaumer@vogelwarte.ch\",\n \"roles\": [\"ContactPerson\", \"ProjectLeader\"]\n }\n ]\n}\n"
- ],
- "skos:relatedMatch": [
- "https://vocab.nerc.ac.uk/collection/MVB/current/MVB000072",
- "https://vocab.nerc.ac.uk/collection/MVB/current/MVB000164"
- ]
- },
- "embargo": {
- "title": "Embargo until",
- "description": "End date of the embargo. The repository will restrict access to the data until the end of the embargo period; at which time, the content will become publicly available automatically. If no `embargo` is provided, it is assumed that there is no embargo.",
- "type": "string",
- "format": "date",
- "examples": ["{\n \"embargo\": \"2024-05-17\"\n}\n"]
- },
- "licenses": {
- "title": "Licenses",
- "description": "The license(s) under which the data is provided. `name` or `path` must be provided. If you're not sure, check out the [Creative Commons License Chooser](https://chooser-beta.creativecommons.org/) and the [Open Data Commons](https://opendatacommons.org/). Usually, a single license if sufficient and preferred. See [Data Package specification](https://datapackage.org/standard/data-package/#licenses). ",
- "type": "array",
- "minItems": 1,
- "items": {
- "title": "License",
- "description": "A license for this descriptor.",
- "type": "object",
- "anyOf": [
- {
- "required": ["name"]
- },
- {
- "required": ["path"]
- }
- ],
- "properties": {
- "name": {
- "title": "Open Definition license identifier",
- "description": "Open Definition license identifier, see [http://licenses.opendefinition.org/](http://licenses.opendefinition.org/)",
- "type": "string",
- "pattern": "^([-a-zA-Z0-9._])+$"
- },
- "path": {
- "title": "Path",
- "description": "A fully qualified URL.",
- "type": "string",
- "pattern": "^((?=[^./~])(?!file:)((?!\\/\\.\\.\\/)(?!\\\\)(?!:\\/\\/).)*|(http|ftp)s?:\\/\\/.*)$",
- "examples": [
- "{\n \"path\": \"file.csv\"\n}\n",
- "{\n \"path\": \"http://example.com/file.csv\"\n}\n"
- ]
- },
- "title": {
- "title": "Title",
- "description": "A human-readable name of the license.",
- "type": "string"
- }
- }
- },
- "examples": [
- "{\n \"licenses\": [\n {\n \"name\": \"CC-BY-4.0\",\n \"path\": \"https://creativecommons.org/licenses/by/4.0/\",\n \"title\": \"Creative Commons Attribution 4.0\"\n }\n ]\n}\n"
- ],
- "skos:narrowMatch": "https://vocab.nerc.ac.uk/collection/MVB/current/MVB000257"
- },
- "id": {
- "title": "ID",
- "description": "A globally unique identifier for the package, typically the [concept DOI](https://support.zenodo.org/help/en-gb/1-upload-deposit/97-what-is-doi-versioning) as full link. Note that you [can reserve the first version DOI prior to publication](https://help.zenodo.org/docs/deposit/describe-records/reserve-doi/#reserve-doi). The corresponding concept DOI can be construct by substracting the ZENODO ID by 1 (`https://doi.org/10.5281/zenodo.14620590` for a DOI reserved as `10.5281/zenodo.14620591`) See [Data Package specification](https://datapackage.org/standard/data-package/#id).",
- "type": "string",
- "examples": ["{\n \"id\": \"https://doi.org/10.5281/zenodo.11207081\"\n}\n"],
- "skos:closeMatch": "https://vocab.nerc.ac.uk/collection/MVB/current/MVB000172"
- },
- "description": {
- "title": "Description",
- "description": "A markdown-formatted string describing the package. You can (and should!) use multiple sentences, but limited to a single paragraph. See [Data Package specification](https://datapackage.org/standard/data-package/#description) and [Datacite metadata schema](https://datacite-metadata-schema.readthedocs.io/en/4.6/properties/description/).",
- "type": "string",
- "format": "textarea",
- "examples": ["{\n \"description\": \"This datapackage contains ...\"\n}\n"],
- "skos:exactMatch": "https://vocab.nerc.ac.uk/collection/MVB/current/MVB000176"
- },
- "version": {
- "title": "Version",
- "description": "A string identifying the version of the package, ideally following [Semantic Versioning](https://semver.org/). See the [Data Package specification](https://datapackage.org/standard/data-package/#version) and [Data Package Version recipe](https://datapackage.org/recipes/data-package-version/).",
- "type": "string",
- "examples": ["{\n \"version\": \"0.0.1\"\n}\n"]
- },
- "relatedIdentifiers": {
- "description": "List of resources related to the package (e.g. papers, project pages, derived datasets, etc.). See [Camtrap DP specification](https://camtrap-dp.tdwg.org/metadata/#relatedIdentifiers) and [Datacite metadata schema](https://datacite-metadata-schema.readthedocs.io/en/4.6/properties/relatedidentifier/).",
- "type": "array",
- "items": {
- "description": "Related identifier.",
- "required": ["relationType", "relatedIdentifier", "relatedIdentifierType"],
- "properties": {
- "relationType": {
- "description": "Description of the relationship between the the package and the related resource. To help you choose the type, think of *'This package {relationType} the related resource'*. [Learn more about these relationships](https://datacite-metadata-schema.readthedocs.io/en/4.6/appendices/appendix-1/relationType/).",
- "skos:exactMatch": "https://schema.datacite.org/meta/kernel-4.6/include/datacite-relationType-v4.xsd",
- "type": "string",
- "enum": [
- "IsCitedBy",
- "Cites",
- "IsSupplementTo",
- "IsSupplementedBy",
- "IsContinuedBy",
- "Continues",
- "IsNewVersionOf",
- "IsPreviousVersionOf",
- "IsPartOf",
- "HasPart",
- "IsPublishedIn",
- "IsReferencedBy",
- "References",
- "IsDocumentedBy",
- "Documents",
- "IsCompiledBy",
- "Compiles",
- "IsVariantFormOf",
- "IsOriginalFormOf",
- "IsIdenticalTo",
- "HasMetadata",
- "IsMetadataFor",
- "Reviews",
- "IsReviewedBy",
- "IsDerivedFrom",
- "IsSourceOf",
- "Describes",
- "IsDescribedBy",
- "HasVersion",
- "IsVersionOf",
- "Requires",
- "IsRequiredBy",
- "Obsoletes",
- "IsObsoletedBy",
- "Collects",
- "IsCollectedBy",
- "HasTranslation",
- "IsTranslationOf"
- ]
- },
- "relatedIdentifier": {
- "description": "Unique identifier of the related resource (e.g. the DOI or URL of the related resource).",
- "type": "string"
- },
- "relatedIdentifierType": {
- "description": "Type of the `relatedIdentifier`. [Learn more about these types](https://datacite-metadata-schema.readthedocs.io/en/4.6/appendices/appendix-1/relatedIdentifierType/).",
- "skos:exactMatch": "https://schema.datacite.org/meta/kernel-4.6/include/datacite-relatedIdentifierType-v4.xsd",
- "type": "string",
- "enum": [
- "DOI",
- "URL",
- "ARK",
- "arXiv",
- "bibcode",
- "CSTR",
- "EAN13",
- "EISSN",
- "Handle",
- "IGSN",
- "ISBN",
- "ISSN",
- "ISTC",
- "LISSN",
- "LSID",
- "PMID",
- "PURL",
- "RRID",
- "UPC",
- "URN",
- "w3id",
- "Other"
- ]
- },
- "resourceTypeGeneral": {
- "description": "General type of the related resource. [Learn more about these type of resources](https://datacite-metadata-schema.readthedocs.io/en/4.6/appendices/appendix-1/resourceTypeGeneral/).",
- "skos:exactMatch": "https://schema.datacite.org/meta/kernel-4.4/include/datacite-resourceType-v4.xsd",
- "type": "string",
- "enum": [
- "Audiovisual",
- "Book",
- "BookChapter",
- "Collection",
- "ComputationalNotebook",
- "ConferencePaper",
- "ConferenceProceeding",
- "DataPaper",
- "Dataset",
- "Dissertation",
- "Event",
- "Image",
- "InteractiveResource",
- "Journal",
- "JournalArticle",
- "Model",
- "OutputManagementPlan",
- "PeerReview",
- "PhysicalObject",
- "Preprint",
- "Report",
- "Service",
- "Software",
- "Sound",
- "Standard",
- "Text",
- "Workflow",
- "Other"
- ]
- }
- }
- },
- "examples": [
- "{\n \"relatedIdentifiers\": [\n {\n \"relationType\": \"IsSupplementTo\",\n \"relatedIdentifier\": \"10.1111/jav.02860\",\n \"relatedIdentifierType\": \"DOI\"\n },\n {\n \"relationType\": \"IsDescribedBy\",\n \"relatedIdentifier\": \"http://dx.doi.org/10.13140/RG.2.2.34477.10721\",\n \"relatedIdentifierType\": \"URL\"\n }\n ]\n}\n"
- ]
- },
- "grants": {
- "title": "Grants",
- "description": "A list of grants and other funding sources of the project.",
- "type": "array",
- "minItems": 1,
- "items": {
- "type": "string"
- },
- "examples": [
- "{\n \"grants\": [\"Hilfsfonds für die Schweizerische Vogelwarte Sempach\"]\n}\n"
- ],
- "skos:exactMatch": "https://vocab.nerc.ac.uk/collection/MVB/current/MVB000123/"
- },
- "keywords": {
- "title": "Keywords",
- "description": "A list of keywords to help users find the package. Also called [`subject`](https://datacite-metadata-schema.readthedocs.io/en/4.6/properties/subject/). See [Data Package specification](https://datapackage.org/standard/data-package/#keywords).",
- "type": "array",
- "minItems": 1,
- "items": {
- "type": "string"
- },
- "examples": [
- "{\n \"keywords\": [\n \"intra-african\",\n \"NDVI\",\n \"geopressure\"\n ]\n}\n"
- ]
- },
- "created": {
- "title": "Created",
- "computed": true,
- "description": "The datetime on which the package was created. See [Data Package specification](https://datapackage.org/standard/data-package/#created).",
- "type": "string",
- "format": "date-time",
- "examples": ["{\n \"created\": \"2024-05-17\"\n}\n"]
- },
- "temporal": {
- "title": "Temporal",
- "computed": true,
- "description": "Temporal coverage of the package. Computed based on [`observations.datetime`](/GeoLocator-DP/core/observations#datetime). Different in format, but equivalent in idea to [GBIF metadata profile](https://ipt.gbif.org/manual/en/ipt/latest/gbif-metadata-profile#temporal-coverage).",
- "type": "object",
- "minItems": 2,
- "maxItems": 2,
- "required": ["start", "end"],
- "properties": {
- "start": {
- "description": "Start date of the first observation. Formatted as an ISO 8601 string (`YYYY-MM-DD`).",
- "type": "string",
- "format": "date"
- },
- "end": {
- "description": "End date of the last observation. Formatted as an ISO 8601 string (`YYYY-MM-DD`).",
- "type": "string",
- "format": "date"
- }
- },
- "examples": [
- "{\n \"temporal\": {\n \"start\": \"2017-01-10\",\n \"end\": \"2019-09-29\"\n }\n}\n"
- ],
- "skos:exactMatch": "https://purl.org/dc/terms/temporal"
- },
- "spatial": {
- "title": "Spatial",
- "computed": true,
- "description": "Spatial coverage of the package, expressed as GeoJSON. Generally computed as the bounding box of `observations`, `paths` and `pressurepath`. Different in format, but equivalent in idea to [GBIF metadata profile](https://ipt.gbif.org/manual/en/ipt/latest/gbif-metadata-profile#geographic-coverage).",
- "type": "object",
- "$ref": "https://geojson.org/schema/GeoJSON.json",
- "examples": [
- "{\n \"spatial\": {\n \"geometry\": {\n \"type\": \"Polygon\",\n \"coordinates\": [[[30.0, -10.0], [35.0, -10.0], [35.0, -5.0], [30.0, -5.0], [30.0, -10.0]]]\n }\n }\n}\n"
- ],
- "skos:exactMatch": "https://purl.org/dc/terms/spatial"
- },
- "taxonomic": {
- "title": "Taxonomic",
- "computed": true,
- "description": "Taxonomic coverage of the package. List of all scientific names of all animals equipped. Computed based on the unique [`tag.scientific_name`](/GeoLocator-DP/core/tags/scientific_name). Different in format, but equivalent in idea to [GBIF metadata profile](https://ipt.gbif.org/manual/en/ipt/latest/gbif-metadata-profile#taxonomic-coverage). When only a single taxon is present, a single string value is allowed.",
- "oneOf": [
- {
- "type": "array",
- "items": {
- "$ref": "#/$defs/taxonomicName"
- }
- },
- {
- "$ref": "#/$defs/taxonomicName"
- }
- ],
- "examples": ["{\n \"taxonomic\": [\"Halcyon senegaloides\"]\n}\n"]
- },
- "numberTags": {
- "title": "Number of tags",
- "computed": true,
- "description": "A list of the number of tags from various category.",
- "type": "object",
- "minItems": 0,
- "maxItems": 15,
- "properties": {
- "tags": {
- "description": "Number of tags in `tags.csv`, thus usually the number of tags produced for the project and equipped on birds.",
- "type": "number",
- "minimum": 0
- },
- "measurements": {
- "description": "Number of tags in `measurements.csv`, thus the number of tags for which some data were retrieved.",
- "type": "number",
- "minimum": 0
- },
- "light": {
- "description": "Number of tags in `measurements.csv` with some light data.",
- "type": "number",
- "minimum": 0
- },
- "pressure": {
- "description": "Number of tags in `measurements.csv` with some pressure data.",
- "type": "number",
- "minimum": 0
- },
- "activity": {
- "description": "Number of tags in `measurements.csv` with some activity or pitch data.",
- "type": "number",
- "minimum": 0
- },
- "temperature_external": {
- "description": "Number of tags in `measurements.csv` with some external temperature data.",
- "type": "number",
- "minimum": 0
- },
- "temperature_internal": {
- "description": "Number of tags in `measurements.csv` with some internal temperature data.",
- "type": "number",
- "minimum": 0
- },
- "magnetic": {
- "description": "Number of tags in `measurements.csv` with some magnetic data.",
- "type": "number",
- "minimum": 0
- },
- "wet_count": {
- "description": "Number of tags in `measurements.csv` with some wet_count data.",
- "type": "number",
- "minimum": 0
- },
- "conductivity": {
- "description": "Number of tags in `measurements.csv` with some conductivity data.",
- "type": "number",
- "minimum": 0
- },
- "paths": {
- "description": "Number of tags in `paths.csv`.",
- "type": "number",
- "minimum": 0
- },
- "pressurepaths": {
- "description": "Number of tags in `pressurepaths.csv`.",
- "type": "number",
- "minimum": 0
- }
- },
- "skos:relatedMatch": "http://vocab.nerc.ac.uk/collection/MVB/current/MVB000227/"
- },
- "bibliographicCitation": {
- "title": "bibliographicCitation",
- "computed": true,
- "description": "Bibliographic/recommended citation for the package. Ideally, same author as [`contributors`](#contributors), same date as [`created`](#created), same title as [`title`](#title) and same doi as [`id`](#id).",
- "type": "string",
- "examples": [
- "{\n \"bibliographicCitation\": \"Nussbaumer, R., & Rime, Y. (2024). Woodland Kingfisher: Migration route and timing of South African Woodland Kingfisher (v1.1). Zenodo. https://doi.org/10.5281/zenodo.11207141\"\n}\n"
- ],
- "skos:exactMatch": [
- "http://purl.org/dc/terms/bibliographicCitation",
- "https://vocab.nerc.ac.uk/collection/MVB/current/MVB000068"
- ]
- },
- "referenceLocation": {
- "title": "Reference location",
- "computed": true,
- "description": "Reference location for the study is used to display the study on a map. Choose a central position for your study, typically the main deployment site. This is required to upload your data on Movebank.",
- "type": "object",
- "minItems": 2,
- "maxItems": 2,
- "required": ["latitude", "longitude"],
- "properties": {
- "latitude": {
- "description": "Reference latitude in degree decimal.",
- "type": "number",
- "minimum": -90,
- "maximum": 90,
- "skos:exactMatch": "http://vocab.nerc.ac.uk/collection/MVB/current/MVB000222"
- },
- "longitude": {
- "description": "Reference longitude in degree decimal.",
- "type": "number",
- "minimum": -180,
- "maximum": 180,
- "skos:exactMatch": "http://vocab.nerc.ac.uk/collection/MVB/current/MVB000223"
- }
- },
- "examples": [
- "{\n \"referenceLocation\": {\n \"latitude\": -13.02,\n \"longitude\": 151.07,\n }\n}\n"
- ],
- "skos:exactMatch": "https://purl.org/dc/terms/Location"
- },
"$schema": {
"title": "Profile",
- "description": "See [Data Package specification](https://datapackage.org/standard/data-package/#dollar-schema). GeoLocator DP further requires this to be the URL of the used GeoLocator DP Profile version.",
+ "description": "URL of the GeoLocator DP profile providing the version information. Use a short Git ref in the URL path. URLs using `refs/tags` are also accepted. See [Data Package specification](https://datapackage.org/standard/data-package/#dollar-schema).",
"type": "string",
"format": "uri",
+ "pattern": "^https://raw\\.githubusercontent\\.com/Rafnuss/GeoLocator-DP/(?:(?:v\\d+\\.\\d+(?:\\.\\d+)?)|dev|(?:refs/tags/(?:v\\d+\\.\\d+(?:\\.\\d+)?|dev)))/geolocator-dp-profile\\.json$",
"examples": [
- "{\n \"$schema\": \"https://raw.githubusercontent.com/Rafnuss/GeoLocator-DP/refs/tags/v0.2/geolocator-dp-profile.json\"\n}\n"
+ "{\n \"$schema\": \"https://raw.githubusercontent.com/Rafnuss/GeoLocator-DP/v1.0/geolocator-dp-profile.json\"\n}\n"
]
},
"resources": {
"title": "Data Resources",
- "description": "See [Data Package specification](https://datapackage.org/standard/data-resource/). GeoLocator DP further requires each object to be a [Tabular Data Resource](https://datapackage.org/standard/data-resource/#tabular) with a specific `name` and `$schema`.",
+ "description": "GeoLocator DP supports tabular resources with a fixed table schema (`tags`, `observations`, `measurements`, `staps`, `twilights`, `paths`, `edges`, `pressurepaths`), a `params` JSON resource, and additional custom resources with non-reserved names. See [Data Package specification](https://datapackage.org/standard/data-resource/).",
"type": "array",
"minItems": 3,
"items": {
@@ -550,17 +44,58 @@
]
},
"type": {
- "description": "Type of the resource. Only `table` are allowed. See [Data Package specification](https://datapackage.org/standard/data-resource/#type).",
+ "description": "Type of the resource. Only `table` is allowed. See [Data Package specification](https://datapackage.org/standard/data-resource/#type).",
"enum": ["table"]
},
"path": {
- "description": "Path or URL to the data file. See [Data Package specification](https://datapackage.org/standard/data-resource/#path)."
+ "description": "Path or URL to a CSV resource file (`.csv`) or a zipped CSV file (`.csv.gz`, `.csv.zip`, `.zip`). See [Data Package specification](https://datapackage.org/standard/data-resource/#path).",
+ "type": "string",
+ "pattern": "^.+\\.(csv|csv\\.gz|csv\\.zip|zip)(\\?.*)?(#.*)?$"
},
"$schema": {
"description": "URL of the used GeoLocator DP Table Schema version. See [Data Package specification](https://datapackage.org/standard/data-resource/#dollar-schema).",
"type": "string",
"format": "uri",
- "pattern": "^https://raw\\.githubusercontent\\.com/Rafnuss/GeoLocator-DP/refs/tags/v\\d+\\.\\d+/.*-table-schema\\.json$"
+ "pattern": "^https://raw\\.githubusercontent\\.com/Rafnuss/GeoLocator-DP/(?:(?:v\\d+\\.\\d+(?:\\.\\d+)?)|dev|(?:refs/tags/(?:v\\d+\\.\\d+(?:\\.\\d+)?|dev)))/.*-table-schema\\.json$"
+ }
+ }
+ },
+ {
+ "required": ["name", "path"],
+ "properties": {
+ "name": {
+ "description": "GeoPressureR parameters resource. This JSON file stores the parameters used to build trajectories in the GeoPressureR workflow (the `param` object, organized as `param$$`).",
+ "const": "params"
+ },
+ "path": {
+ "description": "Path or URL to a JSON file containing GeoPressureR parameters (typically `params.json`).",
+ "type": "string",
+ "pattern": "^.+\\.json(\\?.*)?(#.*)?$"
+ }
+ }
+ },
+ {
+ "required": ["name", "path"],
+ "properties": {
+ "name": {
+ "description": "Identifier of a custom resource. Must not reuse reserved GeoLocator DP resource names.",
+ "type": "string",
+ "not": {
+ "enum": [
+ "tags",
+ "observations",
+ "measurements",
+ "staps",
+ "twilights",
+ "paths",
+ "edges",
+ "pressurepaths",
+ "params"
+ ]
+ }
+ },
+ "path": {
+ "description": "Path or URL to the custom resource file."
}
}
}
diff --git a/measurements-table-schema.json b/measurements-table-schema.json
index 160546a..cebff4b 100644
--- a/measurements-table-schema.json
+++ b/measurements-table-schema.json
@@ -1,7 +1,7 @@
{
"name": "measurements",
"title": "Measurements",
- "description": "`measurements.csv` is a [tabular data](https://datapackage.org/standard/glossary/#tabular-data) resources from a GeoLocator Data Package containing the raw data from the sensors of all tag.\n\n{:.alert .alert-warning}\nCompared to most other data structures, `measurements` combines all sensors and all tag in a single table!",
+ "description": "`measurements.csv` is a [tabular data](https://datapackage.org/standard/glossary/#tabular-data) resource from a GeoLocator Data Package containing raw data from sensors on all tags.\n\n{:.alert .alert-warning}\nNote that data from all sensors and all tags are contained in a single table!",
"$schema": "https://datapackage.org/profiles/2.0/tableschema.json",
"fields": [
{
@@ -15,7 +15,7 @@
},
{
"name": "sensor",
- "description": "Sensor type.\n - `light`: Light-level values measured by a solar geolocator. Range and units may vary by provider and tag settings. Same as https://vocab.nerc.ac.uk/collection/MVB/current/MVB000139/\n - `pressure`: Atmospheric pressure in hPa (or mbar) Same as https://vocab.nerc.ac.uk/collection/MVB/current/MVB000055/\n - `activity`: Measure of the movement performed by the bird, computed from acceleration sensors. Range and method of calculation may vary by the tag provider, model, settings and placement on the animal. In general, higher values indicate more activity. Typically computed as the cumulative sum of the absolute difference of the acceleration along the z-axis. See [doi:10.1186/s40462-018-0137-1](https://doi.org/10.1186/s40462-018-0137-1) (SOI), [doi:10.1111/jav.01068](https://doi.org/10.1111/jav.01068) (Lund) and [migratetech report](https://www.migratetech.co.uk/IntigeoSummary.pdf) for more details. Same as https://vocab.nerc.ac.uk/collection/MVB/current/MVB000114/\n- `pitch`: The pitch of the tag, as measured by the gyroscope, accelerometer and/or magnetometer on the tag. Values are in degree and range from -180 to 180, with positive values indicating backward pitch and negative values indicating forward pitch. Same as https://vocab.nerc.ac.uk/collection/MVB/current/MVB000263/ \n- `temperature_external`: The temperature measured by the tag's sensor pointing outward from the animal. Also called air temperature. Corresponds typically to most temperature sensor. Units: degree Celsius. Same as https://vocab.nerc.ac.uk/collection/MVB/current/MVB000104/\n- `temperature_internal`: The temperature measured by the tag's sensor located between the tag and the animal. Also called body temperature. Units: degree Celsius. Same as https://vocab.nerc.ac.uk/collection/MVB/current/MVB000256/\n- `acceleration_x`: Raw acceleration values provided by the tag for the X axis. Units: m/s^2. Same as https://vocab.nerc.ac.uk/collection/MVB/current/MVB000006/\n- `acceleration_y`: Raw acceleration values provided by the tag for the X axis. Units: m/s^2. Same as https://vocab.nerc.ac.uk/collection/MVB/current/MVB000007/\n- `acceleration_z`: Raw acceleration values provided by the tag for the X axis. Units: m/s^2. Same as https://vocab.nerc.ac.uk/collection/MVB/current/MVB000008/\n- `magnetic_x`: The magnetic field strength measured by the magnetometer for the X axis. Units: microtesla. Same as https://vocab.nerc.ac.uk/collection/MVB/current/MVB000258/\n- `magnetic_y`: The magnetic field strength measured by the magnetometer for the Y axis. Units: microtesla. Same as https://vocab.nerc.ac.uk/collection/MVB/current/MVB000259/\n- `magnetic_z`: The magnetic field strength measured by the magnetometer for the Z axis. Units: microtesla. Same as https://vocab.nerc.ac.uk/collection/MVB/current/MVB000260/\n- `wet_count`: Wet count during a measurement interval from the wet-dry sensor. Unita are usually specific to the device. Same as https://vocab.nerc.ac.uk/collection/MVB/current/MVB000213/\n- `conductivity`: Conductivity measured by the wet-dry sensor. Unit varies by model. Same as https://vocab.nerc.ac.uk/collection/MVB/current/MVB000071/",
+ "description": "Sensor type.\n - `light`: Light-level values measured by a solar geolocator. Range and units may vary by provider and tag settings. Same as https://vocab.nerc.ac.uk/collection/MVB/current/MVB000139/\n - `pressure`: Atmospheric pressure in hPa (or mbar). Same as https://vocab.nerc.ac.uk/collection/MVB/current/MVB000055/\n - `activity`: Measure of movement performed by the bird, computed from acceleration sensors. Range and computation method may vary by tag provider, model, settings, and placement on the animal. In general, higher values indicate more activity. Typically computed as the cumulative sum of the absolute difference of acceleration along the z-axis. See [doi:10.1186/s40462-018-0137-1](https://doi.org/10.1186/s40462-018-0137-1) (SOI), [doi:10.1111/jav.01068](https://doi.org/10.1111/jav.01068) (Lund), and the [migratetech report](https://www.migratetech.co.uk/IntigeoSummary.pdf) for more details. Same as https://vocab.nerc.ac.uk/collection/MVB/current/MVB000114/\n - `mean_acceleration_z`: Mean acceleration along the z-axis, computed from acceleration sensors. Mainly used by SOI devices. This metric is sometimes used as a proxy for pitch and was named `pitch` in GeoLocator DP versions earlier than v1.0.\n - `temperature_external`: Temperature measured by the tag sensor pointing outward from the animal (air temperature). This typically corresponds to the main external temperature sensor. Units: degrees Celsius. Same as https://vocab.nerc.ac.uk/collection/MVB/current/MVB000104/\n - `temperature_internal`: Temperature measured by the tag sensor located between the tag and the animal (body temperature). Units: degrees Celsius. Same as https://vocab.nerc.ac.uk/collection/MVB/current/MVB000256/\n - `acceleration_x`: Raw acceleration values provided by the tag for the X axis. Units: m/s^2. Same as https://vocab.nerc.ac.uk/collection/MVB/current/MVB000006/\n - `acceleration_y`: Raw acceleration values provided by the tag for the Y axis. Units: m/s^2. Same as https://vocab.nerc.ac.uk/collection/MVB/current/MVB000007/\n - `acceleration_z`: Raw acceleration values provided by the tag for the Z axis. Units: m/s^2. Same as https://vocab.nerc.ac.uk/collection/MVB/current/MVB000008/\n - `magnetic_x`: Magnetic field strength measured by the magnetometer for the X axis. Units: microtesla. Same as https://vocab.nerc.ac.uk/collection/MVB/current/MVB000258/\n - `magnetic_y`: Magnetic field strength measured by the magnetometer for the Y axis. Units: microtesla. Same as https://vocab.nerc.ac.uk/collection/MVB/current/MVB000259/\n - `magnetic_z`: Magnetic field strength measured by the magnetometer for the Z axis. Units: microtesla. Same as https://vocab.nerc.ac.uk/collection/MVB/current/MVB000260/\n - `wet_count`: Wet count during a measurement interval from the wet-dry sensor. Units are usually device-specific. Same as https://vocab.nerc.ac.uk/collection/MVB/current/MVB000213/\n - `conductivity`: Conductivity measured by the wet-dry sensor. Unit varies by model. Same as https://vocab.nerc.ac.uk/collection/MVB/current/MVB000071/",
"type": "string",
"constraints": {
"required": true,
@@ -23,7 +23,7 @@
"light",
"pressure",
"activity",
- "pitch",
+ "mean_acceleration_z",
"temperature_internal",
"temperature_external",
"acceleration_x",
@@ -51,7 +51,7 @@
},
{
"name": "value",
- "description": "Value of the measurement taken by the sensor",
+ "description": "Value of the measurement taken by the sensor.",
"type": "number",
"constraints": {
"required": true
@@ -60,7 +60,7 @@
},
{
"name": "label",
- "description": "Labeling of the pressure and acceleration data according to the [labeling chapter of the GeoPressureManual](https://raphaelnussbaumer.com/GeoPressureManual/labelling-tracks.html)",
+ "description": "Labeling of pressure and acceleration data according to the [labeling chapter of the GeoPressureManual](https://raphaelnussbaumer.com/GeoPressureManual/labelling-tracks.html).",
"type": "string",
"constraints": {
"required": false,
diff --git a/observations-table-schema.json b/observations-table-schema.json
index ac5c76c..95dceb4 100644
--- a/observations-table-schema.json
+++ b/observations-table-schema.json
@@ -1,12 +1,12 @@
{
"name": "observations",
"title": "observations",
- "description": "`observations.csv` is a [tabular data](https://datapackage.org/standard/glossary/#tabular-data) resources from a GeoLocator Data Package containing any relevant [events](http://rs.tdwg.org/dwc/terms/Event) (datetime and location) that happened typically on the field and which provide important information for the analysis. These observations must typically include at least the equipment and, if appropriate, the retrieval, but also any ringing control or direct sightings for instance.\n\n{:.alert .alert-info}\nYou can think of `observations` as your log entries in your ringing book.\n\nAn observation is described by at least, the `datetime` of the observation, the location (`latitude` and `longitude`), the `ring_number` of the bird and the type of observations `observation_type` (e.g., equipment, retrieval or control). In addition, we require also `age` and `age_class` (which can be set as unknown `U`).\n\n Also include the ringing events of any control group (i.e., birds ringed but not equipped with a tag).\n\n **Example:** [`observations.csv`](https://github.com/Rafnuss/GeoLocator-DP/blob/main/example/observations.csv)",
+ "description": "`observations.csv` is a [tabular data](https://datapackage.org/standard/glossary/#tabular-data) resource from a GeoLocator Data Package containing relevant [events](http://rs.tdwg.org/dwc/terms/Event) (datetime and location) that typically happen in the field and provide important information for analysis. These observations should include at least equipment and, when appropriate, retrieval events, as well as ringing controls or direct sightings.\n\n{:.alert .alert-info}\nYou can think of `observations` as your log entries in your ringing book.\n\nAn observation is described at minimum by `datetime`, location (`latitude` and `longitude`), `ring_number`, and `observation_type` (e.g., equipment, retrieval, or capture). In addition, `sex` and `age_class` are required (use `U` for unknown `sex` and `0` for unknown `age_class`).\n\nAlso include ringing events for any control group (i.e., birds ringed but not equipped with a tag).\n\n **Example:** [`observations.csv`](https://github.com/Rafnuss/GeoLocator-DP/blob/main/example/observations.csv)",
"$schema": "https://datapackage.org/profiles/2.0/tableschema.json",
"fields": [
{
"name": "ring_number",
- "description": "Ring number associated with the observed species. Foreign key to [`tags.ring_number`](/GeoLocator-DP/core/tags#ring_number).",
+ "description": "Ring number associated with the observed bird. This is the bird-level identifier used to connect observations over time. It is not a strict foreign key because the same `ring_number` can appear in multiple `tags` rows (e.g., multiple deployments on the same bird).",
"type": "string",
"constraints": {
"required": true
@@ -16,7 +16,7 @@
},
{
"name": "tag_id",
- "description": "Unique identifier of the tag. `tag_id` is NOT required in this table so that you can enter any relevant ringed specied (e.g. control group). Foreign key to [`tags.tag_id`](/GeoLocator-DP/core/tags#tag_id).",
+ "description": "Unique identifier of the tag. `tag_id` is NOT required in this table so that you can enter any relevant ringed species (e.g., control group). Foreign key to [`tags.tag_id`](/GeoLocator-DP/core/tags#tag_id). When provided, it should refer to a deployment associated with the same bird (`ring_number`).",
"type": "string",
"constraints": {
"required": false
@@ -25,7 +25,7 @@
},
{
"name": "observation_type",
- "description": "Type of observation. \n - `equipment`: Attachment of the tag on the bird. If you're equipping a new tag at the same time as retrieving an old one from the same bird, create two dedicated rows in the dataset: one for the retrieval and one for the equipment. \n - `retrieval`: Retrieval of the data. Generally through recapture and removal of the tag from the bird but can also be through remote download readout method (see [`tags.readout_method`](core/tags/#readout_method)).\n - `capture`: General case of capture of a bird while not deploying nor retrieving a tag. This option covers the case of (1) recapturing a bird without a device (choose `missing` in `device_status`), (2) the case of a capture before an `equipment` or after a `retrieval` and (3) and capture of individuals from the control group. Recapture/retrap are not hard coded in the dataset, but inferred from consecutive capture of the same `ring_number`. \n - `sighting`: Known presence of the bird on a date and location besides ringing (e.g. direct observation in the field with color ring)\n - `other`: Other type of observation. Avoid using this, and if using, always provide [`observation_comments`](core/observations/#observation_comments).",
+ "description": "Type of observation.\n - `equipment`: Attachment of the tag to the bird. If you equip a new tag at the same time as retrieving an old one from the same bird, create two dedicated rows in the dataset: one for retrieval and one for equipment.\n - `retrieval`: Retrieval of the data, generally through recapture and tag removal, but it can also happen through remote download readout methods (see [`tags.readout_method`](/GeoLocator-DP/core/tags#readout_method)).\n - `capture`: General case of capturing a bird while neither deploying nor retrieving a tag. This option covers (1) recapturing a bird without a device (choose `missing` in `device_status`), (2) a capture before `equipment` or after `retrieval`, and (3) captures of individuals from the control group. Recapture/retrap are not hard-coded in the dataset, but inferred from consecutive captures of the same `ring_number`.\n - `sighting`: Known presence of the bird on a date and location outside ringing (e.g., direct field observation with a color ring).\n - `other`: Any other observation type. Avoid using this; if used, always provide [`observation_comments`](/GeoLocator-DP/core/observations#observation_comments).",
"type": "string",
"constraints": {
"required": true,
@@ -35,7 +35,7 @@
},
{
"name": "datetime",
- "description": "Date and optionally time of the observation. Accepts any valid [ISO 8601](https://wikipedia.org/wiki/ISO_8601) date or datetime string, including date-only (`YYYY-MM-DD`), full datetime in local time (`YYYY-MM-DDThh:mm`), in UTC (`YYYY-MM-DDThh:mmZ`) or any specific timezone ()`YYYY-MM-DDThh:mm+hh:mm`).",
+ "description": "Date and optionally time of the observation. Accepts any valid [ISO 8601](https://wikipedia.org/wiki/ISO_8601) date or datetime string, including date-only (`YYYY-MM-DD`), full datetime in local time (`YYYY-MM-DDThh:mm`), in UTC (`YYYY-MM-DDThh:mmZ`), or in any specific timezone (`YYYY-MM-DDThh:mm+hh:mm`).",
"skos:broadMatch": "http://rs.tdwg.org/dwc/terms/eventDate",
"type": "datetime",
"constraints": {
@@ -88,7 +88,7 @@
},
{
"name": "device_status",
- "description": "Status of the tag itself (not the data inside the tag): \n - `present`: Tag on the bird.\n- `none`: No tag present on the bird and this is expected (e.g. pre-equipmenet, post-removal, or control group). Only for `observation_type='capture'`.\n - `missing`: Tag lost by the bird. Only for `observation_type='capture'`. In case a new tag is deployed on a bird which has lost his previous tag, create two rows: one `capture`-`missing` and one `equipment`-`present`.\n - `unknown`: Only for `observation_type = 'sighting'`. \n\n Can only be `present` for `observation_type` `equipment` or `retrieval`.",
+ "description": "Status of the tag itself (not the data inside the tag):\n - `present`: Tag on the bird.\n - `none`: No tag on the bird and this is expected (e.g., pre-equipment, post-removal, or control group). Only for `observation_type='capture'`.\n - `missing`: Tag lost by the bird. Only for `observation_type='capture'`. If a new tag is deployed on a bird that lost its previous tag, create two rows: one `capture`-`missing` and one `equipment`-`present`.\n - `unknown`: Only for `observation_type='sighting'`.\n\nCan only be `present` for `observation_type` `equipment` or `retrieval`.",
"type": "string",
"skos:relatedMatch": "http://vocab.nerc.ac.uk/collection/MVB/current/MVB000084",
"constraints": {
@@ -112,7 +112,7 @@
},
{
"name": "catching_method",
- "description": "Catching method according to [EURING Exchange Code](https://euring.org/files/documents/E2020ExchangeCodeV201.pdf#page=12). Generally, one of:\n - `M`: *M*isnet\n - `N`: on *n*est\n - `Z`: unknown",
+ "description": "Catching method according to [EURING Exchange Code](https://euring.org/files/documents/E2020ExchangeCodeV201.pdf#page=12). Generally, one of:\n - `M`: *m*ist-net\n - `N`: on *n*est\n - `Z`: unknown",
"type": "string",
"constraints": {
"required": false,
@@ -144,7 +144,7 @@
},
{
"name": "age_class",
- "description": "Life stage of the bird according to the age class in [EURING Exchange Code](https://euring.org/files/documents/E2020ExchangeCodeV201.pdf#page=14). \n- `0`: Unknown\n- `1`: Pullus\n- `2`: Full-grown\n- `3`: 1yr\n- `4`: >1yr\n- `5`: 2yr\n- `6`: >2yr",
+ "description": "Life stage of the bird according to the age class in [EURING Exchange Code](https://euring.org/files/documents/E2020ExchangeCodeV201.pdf#page=14). \n- `0`: Unknown\n- `1`: Pullus\n- `2`: Full-grown\n- `3`: 1yr\n- `4`: >1yr\n- `5`: 2yr\n- `6`: >2yr\n- ...",
"type": "string",
"constraints": {
"required": true,
@@ -191,7 +191,7 @@
},
{
"name": "condition",
- "description": "Condition of bird follow a simplified version of [EURING Exchange Code](https://euring.org/files/documents/E2020ExchangeCodeV201.pdf#page=23). Assumed to be `alive` if not provided",
+ "description": "Condition of the bird following a simplified version of the [EURING Exchange Code](https://euring.org/files/documents/E2020ExchangeCodeV201.pdf#page=23). Assumed to be `alive` if not provided.",
"type": "string",
"constraints": {
"required": false,
@@ -214,7 +214,7 @@
},
{
"name": "wing_length",
- "description": "Maximum chord measurement. See [EURING Exchange Code](https://euring.org/files/documents/E2020ExchangeCodeV201.pdf#page=26). Expressed in milimeters.",
+ "description": "Maximum chord measurement. See [EURING Exchange Code](https://euring.org/files/documents/E2020ExchangeCodeV201.pdf#page=26). Expressed in millimeters.",
"type": "number",
"constraints": {
"required": false,
@@ -261,13 +261,6 @@
"resource": "tags",
"fields": "tag_id"
}
- },
- {
- "fields": "ring_number",
- "reference": {
- "resource": "tags",
- "fields": "ring_number"
- }
}
],
"fieldsMatch": ["superset"]
diff --git a/pages/curation.md b/pages/curation.md
new file mode 100644
index 0000000..fa88c31
--- /dev/null
+++ b/pages/curation.md
@@ -0,0 +1,51 @@
+---
+title: Curation
+background: /assets/curation.jpg
+permalink: /curation/
+---
+
+## 1. Mandatory Technical Validation
+
+All submitted records must pass the automated validation of [`validate_gldp()`](https://raphaelnussbaumer.com/GeoLocatoR/reference/validate_gldp.html).
+
+## 2. Visual Check
+
+In addition to automated checks, each submission must pass visual and metadata sanity checks. Coverage, ringing, and map plots are inspected to ensure they are biologically plausible and free of obvious artifacts.
+
+```r
+GeoLocatoR::plot(pkg, "coverage")
+GeoLocatoR::plot(pkg, "ring")
+GeoLocatoR::plot(pkg, "map")
+print(pkg)
+```
+
+## 3. Metadata Best Practices
+
+### Required
+
+- **Title**: Must start with `GeoLocator Data Package: `.
+- **Access**: Embargoed records are permitted, but duration must be reasonable and justified, typically until first publication.
+- **Description**: Include minimum contextual information such as study species, main study area, project objective, but alos key processing notes that affect reuse. It's also a good place to invite potential users of the data to get in touch.
+
+### Recommended
+
+- **Related works**: Link publications that use the data via related identifiers.
+- **Software/Repository URL**: Provide a link to the GeoPressureTemplate GitHub repository.
+- **Zenodo badge**: Add the Zenodo badge of your repository at the top of the GitHub `README`.
+- **Final interim file**: Update the final interim file on your GitHub repository.
+- **Author and roles**: Assign author roles as completely as possible using Zenodo/DataCite role options.
+
+
+
+Author role definitions:
+
+- **Contact person**: Person to contact for questions about access, use, citation, or additional information.
+- **Project leader**: Person officially designated as head of project (i.e., principal investigator).
+- **Data curator**: Person in charge of assembling and standardizing the geolocator data package and metadata for publication.
+- **Researcher**: Person involved in analyzing geolocator data or results, often running GeoPressure analyses.
+- **Rights holder**: Person or institution owning or managing property rights, including intellectual property rights over the resource.
+- **Supervisor**: Designated administrator over the project, including funding acquisition.
+- **Data collector**: Person responsible for finding, gathering, or collecting geolocator data (often ringers and field assistants).
+- **Other**: Significant contribution not covered by a more specific role (avoid if possible).
+
+
diff --git a/pages/datapackage.md b/pages/datapackage.md
deleted file mode 100644
index 104c891..0000000
--- a/pages/datapackage.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-layout: profile
-title: datapackage.json
-permalink: /datapackage/
-background: /assets/datapackage.png
-toc: true
----
-
-The metadata is critical for describing your dataset and making your record findable. The metadata associated with a GeoLocator DP are expressed in the `datapackage.json` file. It follows exactly the [Data Package](https://datapackage.org/standard/data-package/).
-
-This definition of the metadata map directly Zenodo metadata structure, which follows [DataCite Metadata Schema](https://datacite-metadata-schema.readthedocs.io/). Note that we map datapackage [`contributors`](https://datapackage.org/standard/data-package/#contributors) to [`creator`](https://datacite-metadata-schema.readthedocs.io/en/4.6/properties/creator/) (and not [`contributor`](https://datacite-metadata-schema.readthedocs.io/en/4.6/properties/contributor/)).
-
-In addition, to allow export of a geolocator data package to [Movebank](https://www.movebank.org/), we add some of the specifications from [Movebank Study Attributes](https://www.movebank.org/cms/movebank-content/movebank-attribute-dictionary).
-
-{:.alert .alert-info style="padding-left: 32px;"}
-
-- Properties indicated with `*` are required.
-- Properties indicated with `+` can (and should) be derived/computed directly from the content of the datapackage rather than provided manually.
-- The properties are listed by order of priority/importance with computed properties listed at the bottom as usually less relevant for users.
diff --git a/pages/geopressurer/edges.md b/pages/geopressurer/edges.md
index a915659..c707818 100644
--- a/pages/geopressurer/edges.md
+++ b/pages/geopressurer/edges.md
@@ -2,5 +2,6 @@
layout: schema
title: edges.csv
permalink: /geopressurer/edges/
+background: /assets/edges.jpg
schema: edges-table-schema
---
diff --git a/pages/geopressurer/paths.md b/pages/geopressurer/paths.md
index 1290a96..035f40a 100644
--- a/pages/geopressurer/paths.md
+++ b/pages/geopressurer/paths.md
@@ -2,5 +2,6 @@
layout: schema
title: paths.csv
permalink: /geopressurer/paths/
+background: /assets/paths.jpg
schema: paths-table-schema
---
diff --git a/pages/geopressurer/pressurepaths.md b/pages/geopressurer/pressurepaths.md
index eb3bdc7..66194ed 100644
--- a/pages/geopressurer/pressurepaths.md
+++ b/pages/geopressurer/pressurepaths.md
@@ -2,5 +2,6 @@
layout: schema
title: pressurepaths.csv
permalink: /geopressurer/pressurepaths/
+background: /assets/pressurepaths.jpg
schema: pressurepaths-table-schema
---
diff --git a/pages/geopressurer/staps.md b/pages/geopressurer/staps.md
index 998e58a..7cf4239 100644
--- a/pages/geopressurer/staps.md
+++ b/pages/geopressurer/staps.md
@@ -2,5 +2,6 @@
layout: schema
title: staps.csv
permalink: /geopressurer/staps/
+background: /assets/staps.jpg
schema: staps-table-schema
---
diff --git a/pages/geopressurer/twilights.md b/pages/geopressurer/twilights.md
index 258a1d6..eec299d 100644
--- a/pages/geopressurer/twilights.md
+++ b/pages/geopressurer/twilights.md
@@ -2,5 +2,6 @@
layout: schema
title: twilights.csv
permalink: /geopressurer/twilights/
+background: /assets/twilights.jpg
schema: twilights-table-schema
---
diff --git a/pages/home.md b/pages/home.md
deleted file mode 120000
index 32d46ee..0000000
--- a/pages/home.md
+++ /dev/null
@@ -1 +0,0 @@
-../README.md
\ No newline at end of file
diff --git a/pages/home.md b/pages/home.md
new file mode 100644
index 0000000..90c660c
--- /dev/null
+++ b/pages/home.md
@@ -0,0 +1,115 @@
+---
+title: GeoLocator DP
+background: /assets/home.png
+permalink: /
+description: Data exchange format for geolocator data
+---
+
+**GeoLocator Data Package** (GeoLocator DP) defines a data exchange format for geolocator data. By using a common structure across projects, GeoLocator DP makes data easier to share, compare, and reuse, ultimately supporting bird migration research, conservation, and public outreach.
+
+{:.alert .alert-primary style="padding-left: 32px;"}
+**Ready to publish your GeoLocator Data Package?** Follow the step-by-step practical guide in the [GeoLocator Data Package chapter of the GeoPressureManual](https://raphaelnussbaumer.com/GeoPressureManual/geolocator-create.html) to create, curate, and share your package with confidence.
+
+## Data Package Structure
+
+A GeoLocator Data Package follows the more general [Data Package](https://datapackage.org/) and is organized into three components: (1) the core resources containing raw geolocator data, (2) optional but highly recommended trajectory resources generated with [GeoPressureR](https://raphaelnussbaumer.com/GeoPressureManual/), and (3) a minimal local manifest.
+
+### 1. Core Resources
+
+The core GeoLocator DP resources consist of raw geolocator data and deployment information. These `resources` can be generated without running trajectory analyses.
+
+| File | Description |
+| ------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------- |
+| [`tags.csv`](https://geopressure.org/GeoLocator-DP/core/tags/) | Table of devices used in the study. We assume that a `tag` is only used once on a single animal. |
+| [`measurements.csv`](https://geopressure.org/GeoLocator-DP/core/measurements/) | Table with the raw measurements of all sensors (e.g., light, pressure, ...) for all tags. |
+| [`observations.csv`](https://geopressure.org/GeoLocator-DP/core/observations/) | Table with the field observations associated with tags such as equipment, retrieval, or other events. |
+
+### 2. GeoPressureR Resources
+
+The GeoPressureR extension consists of optional trajectory data generated through the [GeoPressureR workflow analysis](https://raphaelnussbaumer.com/GeoPressureManual/geopressuretemplate-workflow.html).
+
+| File | Description |
+| --------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
+| [`staps.csv`](https://geopressure.org/GeoLocator-DP/geopressurer/staps) | Table of the stationary periods of all tags. |
+| [`paths.csv`](https://geopressure.org/GeoLocator-DP/geopressurer/paths) | Table of the trajectory of all tags, typically most likely path or simulation paths. |
+| [`edges.csv`](https://geopressure.org/GeoLocator-DP/geopressurer/edges) | Table containing the flight information of the edges associated with the paths. |
+| [`twilights.csv`](https://geopressure.org/GeoLocator-DP/geopressurer/twilights) | Table of the twilights estimated from light data for all tags. |
+| [`pressurepaths.csv`](https://geopressure.org/GeoLocator-DP/geopressurer/pressurepaths) | Table of pressure-based paths. |
+| `params.json` | List of [parameters](https://raphaelnussbaumer.com/GeoPressureR/reference/param_create.html) used to run the GeoPressureR workflow. |
+
+### 3. Local Manifest
+
+Following the [Data Package standard](https://datapackage.org/standard/data-package/), each GeoLocator DP contains a [`datapackage.json`](https://github.com/Rafnuss/GeoLocator-DP/blob/main/geolocator-dp-profile.json) file with: (1) a machine-readable index of all data [`resources`](https://datapackage.org/standard/data-resource/), (2) a package-level [`$schema`](https://datapackage.org/standard/data-package/#dollar-schema) pointing to the GeoLocator DP profile version. Unlike previous versions, in the v1.0, the local manifest stays intentionally minimal, while metadata are managed in Zenodo.
+
+## How to contribute?
+
+If you have multi-sensor geolocator data and would like to contribute a GeoLocator Data Package, follow the workflow below.
+
+1. [`create_geopressuretemplate()`](https://raphaelnussbaumer.com/GeoLocatoR/reference/create_geopressuretemplate.html): Set up your local GeoPressureTemplate project folder [[guide](https://raphaelnussbaumer.com/GeoPressureManual/geopressuretemplate-intro.html)].
+2. [`geopressuretemplate()`](https://raphaelnussbaumer.com/GeoPressureR/reference/geopressuretemplate.html): Run trajectory analyses in your GeoPressureTemplate project [[guide](https://raphaelnussbaumer.com/GeoPressureManual/geopressuretemplate-workflow.html)].
+3. [`read_geopressuretemplate()`](https://raphaelnussbaumer.com/GeoLocatoR/reference/read_geopressuretemplate.html): Build your GeoLocator Data Package from the template outputs [[guide](https://raphaelnussbaumer.com/GeoPressureManual/geolocator-create.html)].
+4. Draft the record on [`Zenodo`](https://zenodo.org/) with metadata, reserve the DOI, and select the GeoLocator-DP community (without publishing yet) [[guide](https://help.zenodo.org/docs/share/submit-to-community/)].
+5. [`validate_gldp()`](https://raphaelnussbaumer.com/GeoLocatoR/reference/validate_gldp.html) and [`GeoLocatoR::plot()`](https://raphaelnussbaumer.com/GeoLocatoR/): Validate the package and resolve issues until all checks pass [[guide](https://raphaelnussbaumer.com/GeoPressureManual/geolocator-intro.html)].
+6. Submit for curation and publish the record [[guide](https://help.zenodo.org/docs/share/submit-to-community/)].
+
+
+
+
+
+Why using Zenodo?
+
+1. long-term hosting, DOI assignment, and versioned records,
+2. a simple and reliable way to manage metadata through web forms,
+3. community curation through the [GeoLocator DP Zenodo community](https://zenodo.org/communities/geolocator-dp/).
+
+
+
+{:.alert .alert-danger style="padding-left: 32px;"}
+For the metadata checklist, validation policy, and visual quality checks before release, see the [Curation page]({{ '/curation/' | relative_url }}).
+
+## Resources
+
+
+
+
+
+
+
+ The GeoLocatoR R package is designed to handle GeoLocator DP: creating a DP, adding resources, writing a DP, and reading a DP. It is essentially an extension of the frictionless package for geolocator data.
+
+
+
+
+
+
+
+ The Geolocator Manual R book has a dedicated part on the use of the GeoLocator Data Package. This is a great place to start learning more about how to use it with your GeoPressureTemplate project.
+
+
+
+
+
+ GeoPressureR is the main package to analyze geolocator data. Once a GeoLocator Data Package is created, GeoPressureR is our recommended software to read the data into R and analyze the data.
+
+ Explore the most likely trajectories of all existing data packages on a 3D map with GeoLocatorExplorer.
+
+
+
+
+## How to Cite
+
+> Nussbaumer, R. (2024). GeoLocator-DP: Data exchange format for multi-sensor geolocator. Zenodo. [10.5281/zenodo.14258411](https://doi.org/10.5281/zenodo.14258411)
diff --git a/pages/schema-overview.md b/pages/schema-overview.md
new file mode 100644
index 0000000..d5d0eef
--- /dev/null
+++ b/pages/schema-overview.md
@@ -0,0 +1,55 @@
+---
+title: Overview
+background: /assets/schema-overview.jpg
+permalink: /schema-overview/
+---
+
+
+
+This diagram shows how the GeoLocator DP tables are connected.
+Each table and each column is documented in detail on its own dedicated page.
+Click a table name in the diagram to open that table reference page.
+
+
+How to read this diagram?
+
+
+- Each box is one table of the schema.
+- Each row is one column name in that table.
+- A `*` means the column is required.
+- The key icon marks columns in the [primary key](https://en.wikipedia.org/wiki/Primary_key): values that uniquely identify each row (sometimes using multiple columns together).
+- Arrows show [foreign key](https://en.wikipedia.org/wiki/Foreign_key) relationships: a column in one table points to a row in another table.
+- `...` means additional columns are allowed by the schema but not listed here.
+- Click a table name to open the dedicated page with full column-level details.
+- Hover table names and fields to read descriptions.
+- Hover arrows to inspect which source and target fields are linked.
+
+
+
+
+
+ {% include schema-diagram-embed.html %}
+
diff --git a/paths-table-schema.json b/paths-table-schema.json
index 1a2d279..a2e1d4d 100644
--- a/paths-table-schema.json
+++ b/paths-table-schema.json
@@ -1,7 +1,7 @@
{
"name": "paths",
"title": "Paths",
- "description": "A GeoPressureR `path` contains the positions of a bird's trajectory. \n\n{:.alert .alert-info}\nIn GeoPressureR, there are 4 types of path : `tag`, `most_likely`, `simulation` and `geopressureviz`. See [`paths.type`](#type) for more details. \n\n `path` should always be used in combination with [`staps`](geopressurer/staps) which can be JOIN by `tag_id` and `stap_id`.",
+ "description": "A GeoPressureR `path` contains positions along a bird trajectory.\n\n{:.alert .alert-info}\nIn GeoPressureR, there are 4 path types: `tag`, `most_likely`, `simulation`, and `geopressureviz`. See [`paths.type`](#type) for more details.\n\n`path` should always be used in combination with [`staps`](/GeoLocator-DP/geopressurer/staps), joined by the composite key (`tag_id`, `stap_id`).",
"$schema": "https://datapackage.org/profiles/2.0/tableschema.json",
"fields": [
{
@@ -15,7 +15,7 @@
},
{
"name": "type",
- "description": "One of:\n - `tag`: Create with [`tag2path()`](https://raphaelnussbaumer.com/GeoPressureR/reference/tag2path) from a likelihood map.\n - `most_likely`: Created with [`graph_most_likely()`](https://raphaelnussbaumer.com/GeoPressureR/reference/graph_most_likely.html)\n- `simulation`: created by [`graph_simulation()`](https://raphaelnussbaumer.com/GeoPressureR/reference/graph_simulation): \n- `geopressureviz`: created by [`geopressureviz()`](https://raphaelnussbaumer.com/GeoPressureR/reference/geopressureviz).",
+ "description": "One of:\n - `tag`: Created with [`tag2path()`](https://raphaelnussbaumer.com/GeoPressureR/reference/tag2path) from a likelihood map.\n - `most_likely`: Created with [`graph_most_likely()`](https://raphaelnussbaumer.com/GeoPressureR/reference/graph_most_likely.html).\n - `simulation`: Created by [`graph_simulation()`](https://raphaelnussbaumer.com/GeoPressureR/reference/graph_simulation).\n - `geopressureviz`: Created by [`geopressureviz()`](https://raphaelnussbaumer.com/GeoPressureR/reference/geopressureviz).",
"type": "string",
"constraints": {
"required": true,
@@ -25,7 +25,7 @@
},
{
"name": "stap_id",
- "description": "Identifier of the stationary period. Foreign key to [`staps.stap_id`](/GeoLocator-DP/geopressurer/staps#stap_id)",
+ "description": "Identifier of the stationary period. Together with [`tag_id`](#tag_id), this forms a foreign key to [`staps`](/GeoLocator-DP/geopressurer/staps) (`tag_id`, `stap_id`).",
"type": "number",
"constraints": {
"required": true
@@ -56,43 +56,15 @@
"example": "23.84995",
"skos:exactMatch": "http://rs.tdwg.org/dwc/terms/decimalLongitude"
},
- {
- "name": "ind",
- "description": "Indices of the 2D coordinate of the spatial map defined in [`GeoPressureR::tag_set_map()`](https://raphaelnussbaumer.com/GeoPressureR/reference/tag_set_map) (see also [`GeoPressureR::map_expand()`](https://raphaelnussbaumer.com/GeoPressureR/reference/map_expand). Useful to retrieve information on the graph (e.g. [`GeoPressureR::path2edge()`](https://raphaelnussbaumer.com/GeoPressureR/reference/path2edge). This value is the main way to create a path in GeoPressureR through [`GeoPressureR::ind2path()`](https://raphaelnussbaumer.com/GeoPressureR/reference/ind2path).",
- "type": "integer",
- "constraints": {
- "required": false,
- "minimum": 1
- },
- "example": "23343"
- },
{
"name": "j",
- "description": "Unique identifier for each trajectory. Only useful for `paths.type='simulation'`. Integer from `1` to `nj` as defined in [`GeoPressureR::graph_simulation()`](https://raphaelnussbaumer.com/GeoPressureR/reference/graph_simulation)`.",
+ "description": "Unique identifier for each trajectory. Only useful for `paths.type='simulation'`. Integer from `1` to `nj` as defined in [`GeoPressureR::graph_simulation()`](https://raphaelnussbaumer.com/GeoPressureR/reference/graph_simulation).",
"type": "integer",
"constraints": {
"required": false,
"minimum": 1
},
"example": "1"
- },
- {
- "name": "interp",
- "description": "Only useful for `paths.type='tag'`. Boolean value to indicate if the position was interpolated as defined by the `interp` parameter in [`GeoPressureR::tag2path()`](https://raphaelnussbaumer.com/GeoPressureR/reference/tag2path).",
- "type": "boolean",
- "constraints": {
- "required": false
- },
- "example": "true"
- },
- {
- "name": "known",
- "description": "Boolean to indicate if the position is taken from a known value. Genearally, `TRUE` if [`staps.known_lat`](geopressurer/staps#known_lat) and [`staps.known_lon`](geopressurer/staps#known_lon) provided. Only different if `paths.type='tag'` and `use_known=FALSE` used in [`GeoPressureR::tag2path()`](https://raphaelnussbaumer.com/GeoPressureR/reference/tag2path).",
- "type": "boolean",
- "constraints": {
- "required": false
- },
- "example": "true"
}
],
"missingValues": ["", "NA"],
@@ -105,10 +77,10 @@
}
},
{
- "fields": "stap_id",
+ "fields": ["tag_id", "stap_id"],
"reference": {
"resource": "staps",
- "fields": "stap_id"
+ "fields": ["tag_id", "stap_id"]
}
}
],
diff --git a/pressurepaths-table-schema.json b/pressurepaths-table-schema.json
index 1345acb..2bc7209 100644
--- a/pressurepaths-table-schema.json
+++ b/pressurepaths-table-schema.json
@@ -1,7 +1,7 @@
{
"name": "pressurepaths",
"title": "Pressurepaths",
- "description": "{:.alert .alert-info}\nA GeoPressureR `pressurepath` contains the ERA5 variables along the trajectory of the bird on an hourly interval and using the exact location of the bird (accounting of flight). [Read more about pressurepath on the GeoPressureManual](https://raphaelnussbaumer.com/GeoPressureManual/pressurepath.html) \n\nSimilarly to [`path`](geopressurer/paths), there are 4 types of pressurepath : `tag`, `most_likely`, `simulation` and `geopressureviz`. See [`pressurepaths.type`](#type) for more details. \n\n `pressurepath` should be used in combination with [`staps`](geopressurer/staps) and [`paths`](geopressurer/paths) which can be JOIN by `tag_id` and `stap_id`. \n\n{:.alert .alert-warning}\n The definition below does not list the ERA5 variables which can (and should!) be added to the table as additional columns (e.g. `'altitude'` or `'surface_pressure'`). Read more about these variable in [the documentation of `pressurepath_create()`](https://raphaelnussbaumer.com/GeoPressureR/reference/pressurepath_create.html#arg-variable)",
+ "description": "{:.alert .alert-info}\nA GeoPressureR `pressurepath` contains ERA5 variables along the bird trajectory at hourly intervals, using the exact bird location (including flight segments). [Read more about pressurepaths in the GeoPressureManual](https://raphaelnussbaumer.com/GeoPressureManual/pressurepath.html)\n\nSimilarly to [`path`](/GeoLocator-DP/geopressurer/paths), there are 4 `pressurepath` types: `tag`, `most_likely`, `simulation`, and `geopressureviz`. See [`pressurepaths.type`](#type) for more details.\n\n`pressurepath` should be used in combination with [`staps`](/GeoLocator-DP/geopressurer/staps) and [`paths`](/GeoLocator-DP/geopressurer/paths). Joins are performed on `tag_id` and, for stationary rows, `stap_id`.\n\n{:.alert .alert-warning}\nOnly `tag_id` is defined as a strict foreign key here. `stap_id` can be decimal during migration segments, so it cannot be enforced as a strict foreign key to `staps` in all rows.\n\nThe definition below does not list ERA5 variables, which can (and should!) be added to the table as additional columns (e.g., `'altitude'` or `'surface_pressure'`). Read more about these variables in [the documentation of `pressurepath_create()`](https://raphaelnussbaumer.com/GeoPressureR/reference/pressurepath_create.html#arg-variable).",
"$schema": "https://datapackage.org/profiles/2.0/tableschema.json",
"fields": [
{
@@ -25,7 +25,7 @@
},
{
"name": "stap_id",
- "description": "Identifier of the stationary period. Foreign key to [`staps.stap_id`](/GeoLocator-DP/geopressurer/staps#stap_id). A main different with `pressurepath` is that `stap_id` can have decimal value indicating a pressure measurement taken while in migration between two 'integer' stationary periods.",
+ "description": "Identifier of the stationary-period index for the trajectory. Integer values correspond to `staps.stap_id` within the same `tag_id`; decimal values indicate pressure measurements taken during migration between two integer stationary periods. For this reason, `stap_id` is not a strict foreign key in this table.",
"type": "number",
"constraints": {
"required": true
@@ -34,7 +34,7 @@
},
{
"name": "type",
- "description": "One of:\n - `tag`: Create with [`tag2path()`](https://raphaelnussbaumer.com/GeoPressureR/reference/tag2path) from a likelihood map.\n - `most_likely`: Created with [`graph_most_likely()`](https://raphaelnussbaumer.com/GeoPressureR/reference/graph_most_likely.html)\n- `simulation`: created by [`graph_simulation()`](https://raphaelnussbaumer.com/GeoPressureR/reference/graph_simulation): \n- `geopressureviz`: created by [`geopressureviz()`](https://raphaelnussbaumer.com/GeoPressureR/reference/geopressureviz).",
+ "description": "One of:\n - `tag`: Created with [`tag2path()`](https://raphaelnussbaumer.com/GeoPressureR/reference/tag2path) from a likelihood map.\n - `most_likely`: Created with [`graph_most_likely()`](https://raphaelnussbaumer.com/GeoPressureR/reference/graph_most_likely.html).\n - `simulation`: Created by [`graph_simulation()`](https://raphaelnussbaumer.com/GeoPressureR/reference/graph_simulation).\n - `geopressureviz`: Created by [`geopressureviz()`](https://raphaelnussbaumer.com/GeoPressureR/reference/geopressureviz).",
"type": "string",
"constraints": {
"required": true,
@@ -44,7 +44,7 @@
},
{
"name": "lat",
- "description": "Latitude of the stationary period.",
+ "description": "Latitude of the trajectory position at this timestamp.",
"type": "number",
"constraints": {
"required": true,
@@ -56,7 +56,7 @@
},
{
"name": "lon",
- "description": "Longitude of the stationary period.",
+ "description": "Longitude of the trajectory position at this timestamp.",
"type": "number",
"constraints": {
"required": true,
@@ -68,7 +68,7 @@
},
{
"name": "j",
- "description": "Only useful for `paths.type='simulation'`. Unique identifier for each trajectory, integer from `1` to `nj` as defined in [`GeoPressureR::graph_simulation()`](https://raphaelnussbaumer.com/GeoPressureR/reference/graph_simulation)`.",
+ "description": "Only useful for `pressurepaths.type='simulation'`. Unique identifier for each trajectory, integer from `1` to `nj` as defined in [`GeoPressureR::graph_simulation()`](https://raphaelnussbaumer.com/GeoPressureR/reference/graph_simulation).",
"type": "integer",
"constraints": {
"required": false,
@@ -85,13 +85,6 @@
"resource": "tags",
"fields": "tag_id"
}
- },
- {
- "fields": "stap_id",
- "reference": {
- "resource": "staps",
- "fields": "stap_id"
- }
}
],
"fieldsMatch": ["partial"]
diff --git a/staps-table-schema.json b/staps-table-schema.json
index 5a9707a..e079805 100644
--- a/staps-table-schema.json
+++ b/staps-table-schema.json
@@ -1,7 +1,7 @@
{
"name": "staps",
"title": "Stationary periods",
- "description": "Stationary period (stap) is [a key concept of the GeoPressureR workflow](https://raphaelnussbaumer.com/GeoPressureManual/tag-object#label-tag-into-stationary-periods) which descritize the trajectory of a bird in time and space. During a single stap, the bird is assumed to remain at the same location (+/- tens of kilometers). [`flight`](https://raphaelnussbaumer.com/GeoPressureR/reference/stap2flight) is the 'converse' of `stap`, with `flight.start` corresponding to an `stap.end` and reciprocly. \n\n{:.alert .alert-info}\n`stap` are typically estimated by [`GeoPressureR::tag_label_stap()`](https://raphaelnussbaumer.com/GeoPressureR/reference/tag_label_stap) based on the labels `'flight'` assigned to the pressure or acceleration measurements ([`measurements.label`](/GeoLocator-DP/core/measurements/#label)). See the [GeoPressureManual](https://raphaelnussbaumer.com/GeoPressureManual/labelling-tracks) for more details.",
+ "description": "A stationary period (`stap`) is [a key concept in the GeoPressureR workflow](https://raphaelnussbaumer.com/GeoPressureManual/tag-object#label-tag-into-stationary-periods) that discretizes a bird trajectory in time and space. During a single `stap`, the bird is assumed to remain at the same location (+/- tens of kilometers). [`flight`](https://raphaelnussbaumer.com/GeoPressureR/reference/stap2flight) is the converse of `stap`, with `flight.start` corresponding to a `stap.end`, and vice versa.\n\n{:.alert .alert-info}\n`stap_id` is indexed within each `tag_id` (it is not globally unique), so the table key is the composite pair (`tag_id`, `stap_id`). `staps` are typically estimated by [`GeoPressureR::tag_label_stap()`](https://raphaelnussbaumer.com/GeoPressureR/reference/tag_label_stap) based on the `'flight'` labels assigned to pressure or acceleration measurements ([`measurements.label`](/GeoLocator-DP/core/measurements#label)). See the [GeoPressureManual](https://raphaelnussbaumer.com/GeoPressureManual/labelling-tracks) for more details.",
"$schema": "https://datapackage.org/profiles/2.0/tableschema.json",
"fields": [
{
@@ -15,7 +15,7 @@
},
{
"name": "stap_id",
- "description": "Identifier of the stationary period to which the twilight belong to.",
+ "description": "Identifier of the stationary period for a given `tag_id`.",
"type": "number",
"constraints": {
"required": true,
@@ -66,15 +66,6 @@
},
"example": "23.84995",
"skos:exactMatch": "http://rs.tdwg.org/dwc/terms/decimalLongitude"
- },
- {
- "name": "include",
- "description": "Boolean value to indicate if the stationary period should be included in the model. This value is typically assigned by [`GeoPressureR::tag_set_map()`](https://raphaelnussbaumer.com/GeoPressureR/reference/tag_set_map).",
- "type": "boolean",
- "constraints": {
- "required": false
- },
- "example": "true"
}
],
"missingValues": ["", "NA"],
@@ -87,5 +78,6 @@
}
}
],
+ "primaryKey": ["tag_id", "stap_id"],
"fieldsMatch": ["superset"]
}
diff --git a/tags-table-schema.json b/tags-table-schema.json
index 7104515..4b9d5df 100644
--- a/tags-table-schema.json
+++ b/tags-table-schema.json
@@ -1,7 +1,7 @@
{
"name": "tags",
"title": "Tags",
- "description": "`tags.csv` is a [tabular data](https://datapackage.org/standard/glossary/#tabular-data) resources from a GeoLocator Data Package. As we assumes that a tag is only deployed once on a single species, this table contains information related to the device, the deployment and the animal equipped. Data collected on the bird which might be changing over time (e.g., `age`) should be provided in the [`observations`](/GeoLocator-DP/GeoLocator-DP/core/observations) table.\n\nAdditional data can be provided by following the [Movebank tag attribute dictionary](https://www.movebank.org/cms/movebank-content/movebank-attribute-dictionary#tag_attributes) and [Movebank deployment attribute dictionary](https://www.movebank.org/cms/movebank-content/movebank-attribute-dictionary#deployment_attributes). \n\n **Example:** [`tag.csv`](https://github.com/Rafnuss/GeoLocator-DP/blob/main/example/tags.csv)",
+ "description": "`tags.csv` is a [tabular data](https://datapackage.org/standard/glossary/#tabular-data) resource from a GeoLocator Data Package. Each tag listed in this table is assumed to have been deployed only once on a single bird. This table contains information about the device, the deployment, and the equipped bird. Data collected on the bird that may change over time (e.g., `age_class`) should be provided in the [`observations`](/GeoLocator-DP/core/observations) table.\n\nAdditional data can be provided by following the [Movebank tag attribute dictionary](https://www.movebank.org/cms/movebank-content/movebank-attribute-dictionary#tag_attributes) and [Movebank deployment attribute dictionary](https://www.movebank.org/cms/movebank-content/movebank-attribute-dictionary#deployment_attributes).\n\n **Example:** [`tags.csv`](https://github.com/Rafnuss/GeoLocator-DP/blob/main/example/tags.csv)",
"$schema": "https://datapackage.org/profiles/2.0/tableschema.json",
"fields": [
{
@@ -26,7 +26,7 @@
},
{
"name": "ring_number",
- "description": "Ring number associated with the tagged species. Use `null` if the tag was not deployed.",
+ "description": "Ring number associated with the tagged bird. This value is not unique at table level because the same bird can receive multiple tag deployments (`tag_id`).",
"type": "string",
"constraints": {
"required": true
@@ -36,7 +36,7 @@
},
{
"name": "scientific_name",
- "description": "Scientific name of the tagged species. Use `null` if the tag was not deployed.",
+ "description": "Scientific name of the tagged species.",
"type": "string",
"constraints": {
"required": true
@@ -59,7 +59,7 @@
},
{
"name": "model",
- "description": "Model/design/version of the tag. Any specification of the device able to identify it.",
+ "description": "Model/design/version of the tag. Any device specification that can identify it.",
"type": "string",
"constraints": {
"required": true
@@ -91,7 +91,7 @@
},
{
"name": "attachment_type",
- "description": "The way a tag is attached to an animal. Use values from [Movebank `attachment type` concept](https://vocab.nerc.ac.uk/collection/MVB/current/MVB000052) values if possible. Assumed to be `harness` if not provided. You can also provide the material used.",
+ "description": "The way a tag is attached to an animal. Use values from the [Movebank `attachment type` concept](https://vocab.nerc.ac.uk/collection/MVB/current/MVB000052) if possible. Assumed to be `harness` if not provided. You can also provide the material used.",
"type": "string",
"constraints": {
"required": false
@@ -102,7 +102,7 @@
{
"name": "readout_method",
"type": "string",
- "description": "The way the data are received from the tag. Use value from [Movebank `tag readout method` concept](https://vocab.nerc.ac.uk/collection/MVB/current/MVB000188/) if possible. Assumed to be `tag-retrieval` if not provided",
+ "description": "The way the data are received from the tag. Use values from the [Movebank `tag readout method` concept](https://vocab.nerc.ac.uk/collection/MVB/current/MVB000188/) if possible. Assumed to be `tag-retrieval` if not provided.",
"constraints": {
"required": false
},
@@ -111,7 +111,7 @@
},
{
"name": "tag_comments",
- "description": "Comments or notes about the tag, deployment or animal.",
+ "description": "Comments or notes about the tag, deployment, or animal. Use this field to provide additional information that does not fit in other fields, such as data-quality issues, deployment/retrieval details, or analysis notes (e.g., labeling effort, quality checks, or issues encountered).",
"type": "string",
"constraints": {
"required": false
diff --git a/tests/helpers.py b/tests/helpers.py
deleted file mode 100644
index cfcb620..0000000
--- a/tests/helpers.py
+++ /dev/null
@@ -1,57 +0,0 @@
-import sys
-from pathlib import Path
-from pprint import pprint
-from typing import Optional, List
-from frictionless import validate
-
-
-THIS_SCRIPT_PATH = Path(__file__).parent
-REPOSITORY_ROOT_PATH = THIS_SCRIPT_PATH / ".."
-PROFILE_PATH = REPOSITORY_ROOT_PATH / "geolocator-dp-profile.json"
-TABLE_SCHEMA_PATHS = [
- REPOSITORY_ROOT_PATH / "observations-table-schema.json",
- REPOSITORY_ROOT_PATH / "tags-table-schema.json",
- REPOSITORY_ROOT_PATH / "measurements-table-schema.json",
- REPOSITORY_ROOT_PATH / "staps-table-schema.json",
- REPOSITORY_ROOT_PATH / "twilights-table-schema.json",
- REPOSITORY_ROOT_PATH / "paths-table-schema.json",
- REPOSITORY_ROOT_PATH / "edges-table-schema.json",
- REPOSITORY_ROOT_PATH / "pressurepaths-table-schema.json",
-]
-
-
-def validate_package_print_and_exit(
- descriptor_data: dict, paths_to_delete: Optional[List] = None
-) -> None:
- report = validate(descriptor_data)
-
- # Cleanup
- if paths_to_delete is not None:
- for path in paths_to_delete:
- path.unlink()
-
- if report.valid:
- print("✔︎ valid package")
- sys.exit(0)
- else:
- print("✕ valid package, errors:")
- if report.errors:
- print("Top-level errors : ")
- for err in report.errors:
- pprint(err)
-
- for task in report.tasks:
- if len(task.errors) != 0:
- print(f"Errors for resource {task.name}:")
-
- if len(task.errors) == 1:
- errors_to_print = [
- task.error
- ] # Weird frictionless API design: must use .error if only one error...
- else:
- errors_to_print = task.errors
-
- for task_err in errors_to_print:
- pprint(task_err)
-
- sys.exit(1)
diff --git a/tests/requirements.txt b/tests/requirements.txt
index 390d8ae..f628024 100644
--- a/tests/requirements.txt
+++ b/tests/requirements.txt
@@ -1,46 +1,2 @@
-attrs==23.1.0
-black==21.9b0
-certifi==2021.10.8
-chardet==4.0.0
-charset-normalizer==2.0.7
-click==8.0.3
-colorama==0.4.4
-decorator==5.1.0
+# Minimal dependencies for tests/validate_profile_and_schemas.py
frictionless>=5.13.1
-humanize==4.6.0
-idna==3.3
-isodate==0.6.0
-Jinja2==3.1.2
-jsonschema>=4.20
-markdown-it-py==2.2.0
-marko==1.1.0
-MarkupSafe==2.1.2
-mdurl==0.1.2
-mypy==0.910
-mypy-extensions==0.4.3
-pathspec==0.9.0
-petl==1.7.4
-platformdirs==2.4.0
-pydantic>=2.0
-Pygments==2.15.1
-pyrsistent==0.18.0
-python-dateutil==2.8.2
-python-slugify==5.0.2
-PyYAML==6.0
-regex==2021.10.23
-reportbro-simpleeval==0.9.11
-requests==2.26.0
-rfc3986==1.5.0
-rich==13.3.5
-shellingham==1.4.0
-simpleeval==0.9.11
-six==1.16.0
-stringcase==1.2.0
-tabulate==0.9.0
-text-unidecode==1.3
-toml==0.10.2
-tomli==1.2.1
-typer>=0.12
-typing_extensions==4.6.1
-urllib3==1.26.7
-validators==0.18.2
diff --git a/tests/validate_profile_and_schemas.py b/tests/validate_profile_and_schemas.py
index b253fdf..03e3294 100644
--- a/tests/validate_profile_and_schemas.py
+++ b/tests/validate_profile_and_schemas.py
@@ -3,19 +3,40 @@
import sys
import json
from pathlib import Path
-from typing import List
+from typing import Dict, List, Optional
from frictionless import Schema
-from helpers import PROFILE_PATH, TABLE_SCHEMA_PATHS
+THIS_SCRIPT_PATH = Path(__file__).parent
+REPOSITORY_ROOT_PATH = THIS_SCRIPT_PATH / ".."
+PROFILE_PATH = REPOSITORY_ROOT_PATH / "geolocator-dp-profile.json"
+TABLE_SCHEMA_PATHS = [
+ REPOSITORY_ROOT_PATH / "observations-table-schema.json",
+ REPOSITORY_ROOT_PATH / "tags-table-schema.json",
+ REPOSITORY_ROOT_PATH / "measurements-table-schema.json",
+ REPOSITORY_ROOT_PATH / "staps-table-schema.json",
+ REPOSITORY_ROOT_PATH / "twilights-table-schema.json",
+ REPOSITORY_ROOT_PATH / "paths-table-schema.json",
+ REPOSITORY_ROOT_PATH / "edges-table-schema.json",
+ REPOSITORY_ROOT_PATH / "pressurepaths-table-schema.json",
+]
-def validate_json(filepath: Path) -> bool:
+EXPECTED_SCHEMA_RESOURCES = {
+ "tags",
+ "observations",
+ "measurements",
+ "staps",
+ "twilights",
+ "paths",
+ "edges",
+ "pressurepaths",
+}
+
+def load_json(filepath: Path) -> Optional[dict]:
with open(filepath) as file:
try:
- json.load(file)
+ return json.load(file)
except json.decoder.JSONDecodeError:
- return False
- else:
- return True
+ return None
def validate_schema(file_path: Path) -> bool:
@@ -32,12 +53,124 @@ def get_schema_metadata_error_messages(file_path: Path) -> List[str]:
return [err.message for err in report.errors]
+def _listify_fields(fields) -> List[str]:
+ if isinstance(fields, str):
+ return [fields]
+ if isinstance(fields, list):
+ return [field for field in fields if isinstance(field, str)]
+ return []
+
+
+def _get_schema_fields(descriptor: dict) -> set:
+ fields = descriptor.get("fields", [])
+ return {
+ field.get("name")
+ for field in fields
+ if isinstance(field, dict) and isinstance(field.get("name"), str)
+ }
+
+
+def check_schema_coherence(schema_descriptors: Dict[Path, dict]) -> bool:
+ encountered_errors = False
+ resource_to_paths: Dict[str, List[Path]] = {}
+
+ # 1) filename <-> schema name consistency
+ for schema_path, descriptor in schema_descriptors.items():
+ schema_name = descriptor.get("name")
+ expected_name = schema_path.name.replace("-table-schema.json", "")
+
+ if not isinstance(schema_name, str):
+ print(f"✕ {schema_path.name}: missing or non-string `name`")
+ encountered_errors = True
+ continue
+
+ resource_to_paths.setdefault(schema_name, []).append(schema_path)
+
+ if schema_name != expected_name:
+ print(
+ f"✕ {schema_path.name}: schema `name` is `{schema_name}` but expected `{expected_name}`"
+ )
+ encountered_errors = True
+
+ # 2) expected resources exist exactly once
+ observed_resources = set(resource_to_paths.keys())
+ missing_resources = sorted(EXPECTED_SCHEMA_RESOURCES - observed_resources)
+ unexpected_resources = sorted(observed_resources - EXPECTED_SCHEMA_RESOURCES)
+
+ for resource in missing_resources:
+ print(f"✕ schema resources: missing expected resource `{resource}`")
+ encountered_errors = True
+
+ for resource in unexpected_resources:
+ print(f"✕ schema resources: unexpected resource `{resource}`")
+ encountered_errors = True
+
+ for resource, paths in sorted(resource_to_paths.items()):
+ if len(paths) > 1:
+ path_list = ", ".join(path.name for path in paths)
+ print(
+ f"✕ schema resources: resource `{resource}` is defined more than once ({path_list})"
+ )
+ encountered_errors = True
+
+ # 3) foreign keys reference existing resources and target fields
+ fields_by_resource: Dict[str, set] = {}
+ for resource, paths in resource_to_paths.items():
+ if len(paths) == 1:
+ fields_by_resource[resource] = _get_schema_fields(schema_descriptors[paths[0]])
+
+ for schema_path, descriptor in schema_descriptors.items():
+ foreign_keys = descriptor.get("foreignKeys", [])
+ if not isinstance(foreign_keys, list):
+ continue
+
+ for foreign_key in foreign_keys:
+ if not isinstance(foreign_key, dict):
+ continue
+
+ reference = foreign_key.get("reference", {})
+ if not isinstance(reference, dict):
+ print(f"✕ {schema_path.name}: malformed foreign key reference")
+ encountered_errors = True
+ continue
+
+ target_resource = reference.get("resource")
+ target_fields = _listify_fields(reference.get("fields"))
+
+ if not isinstance(target_resource, str):
+ print(f"✕ {schema_path.name}: foreign key reference missing `resource`")
+ encountered_errors = True
+ continue
+
+ if target_resource not in resource_to_paths:
+ print(
+ f"✕ {schema_path.name}: foreign key references unknown resource `{target_resource}`"
+ )
+ encountered_errors = True
+ continue
+
+ target_resource_fields = fields_by_resource.get(target_resource, set())
+ missing_target_fields = [
+ field for field in target_fields if field not in target_resource_fields
+ ]
+
+ if missing_target_fields:
+ fields_str = ", ".join(missing_target_fields)
+ print(
+ f"✕ {schema_path.name}: foreign key references missing field(s) in `{target_resource}`: {fields_str}"
+ )
+ encountered_errors = True
+
+ return not encountered_errors
+
+
if __name__ == "__main__":
encountered_errors = False
+ schema_descriptors: Dict[Path, dict] = {}
print(PROFILE_PATH.name)
- result = validate_json(PROFILE_PATH)
- if result is True:
+ profile_json = load_json(PROFILE_PATH)
+ if profile_json is not None:
print("✔︎ valid JSON")
else:
print("✕ valid JSON")
@@ -46,7 +179,9 @@ def get_schema_metadata_error_messages(file_path: Path) -> List[str]:
for table_schema in TABLE_SCHEMA_PATHS:
print(f"\n{table_schema.name}")
- if validate_json(table_schema):
+ schema_json = load_json(table_schema)
+ if schema_json is not None:
+ schema_descriptors[table_schema] = schema_json
print("✔︎ valid JSON")
if validate_schema(table_schema):
print("✔︎ valid Table Schema")
@@ -59,6 +194,12 @@ def get_schema_metadata_error_messages(file_path: Path) -> List[str]:
print("✕ valid JSON")
encountered_errors = True
+ print("\nSchema coherence")
+ if check_schema_coherence(schema_descriptors):
+ print("✔︎ schema coherence checks passed")
+ else:
+ encountered_errors = True
+
if encountered_errors:
print("Errors were encountered")
sys.exit(1)
diff --git a/twilights-table-schema.json b/twilights-table-schema.json
index 52eb32b..a102bb3 100644
--- a/twilights-table-schema.json
+++ b/twilights-table-schema.json
@@ -1,7 +1,7 @@
{
"name": "twilights",
"title": "Twilights",
- "description": "Table with twilights data inferred from light data for all tags. Twilight data is typically computed with [`GeoPressureR::twilight_create()`](https://raphaelnussbaumer.com/GeoPressureR/reference/twilight_create.html).",
+ "description": "Table containing twilight data inferred from light data for all tags. Twilight data is typically computed with [`GeoPressureR::twilight_create()`](https://raphaelnussbaumer.com/GeoPressureR/reference/twilight_create.html).",
"$schema": "https://datapackage.org/profiles/2.0/tableschema.json",
"fields": [
{
@@ -15,7 +15,7 @@
},
{
"name": "twilight",
- "description": "Date and time of the twilights. Formatted as an ISO 8601 string with timezone designator `YYYY-MM-DDThh:mm:ssZ`.",
+ "description": "Date and time of the twilight event. Formatted as an ISO 8601 string with timezone designator `YYYY-MM-DDThh:mm:ssZ`.",
"type": "datetime",
"constraints": {
"required": true
@@ -34,7 +34,7 @@
},
{
"name": "label",
- "description": "Labeling of the twilight data according to the [GeoPressureManual](https://raphaelnussbaumer.com/GeoPressureManual/light-map.html#manual-labelling-of-twilight). The value `discard` indicates that the twilight should not be used for geopositioning. Any other value can be use without affecting the workflow, typically set to `stap_id` allows to visualize which twilight belong to the same stationary period on trainset.",
+ "description": "Labeling of twilight data according to the [GeoPressureManual](https://raphaelnussbaumer.com/GeoPressureManual/light-map.html#manual-labelling-of-twilight). The value `discard` indicates that the twilight should not be used for geopositioning. Any other value can be used without affecting the workflow; setting it to `stap_id` typically helps visualize which twilights belong to the same stationary period in the training set.",
"type": "string",
"constraints": {
"required": false