-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add example for annotating phenology data within Grafana
- Loading branch information
Showing
5 changed files
with
377 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
{ | ||
"overwrite": true, | ||
"dashboard": { | ||
"annotations": { | ||
"list": [ | ||
{ | ||
"builtIn": 1, | ||
"datasource": "-- Grafana --", | ||
"enable": true, | ||
"hide": true, | ||
"iconColor": "rgba(0, 211, 255, 1)", | ||
"limit": 100, | ||
"name": "Annotations & Alerts", | ||
"showIn": 0, | ||
"type": "dashboard" | ||
}, | ||
{ | ||
"datasource": "phenodata-mellifera", | ||
"enable": true, | ||
"hide": false, | ||
"iconColor": "rgba(255, 96, 96, 1)", | ||
"limit": 100, | ||
"name": "Flowering Events Müncheberg", | ||
"query": "flowering:type=observations&station=müncheberg", | ||
"showIn": 0, | ||
"tags": [], | ||
"type": "tags" | ||
}, | ||
{ | ||
"datasource": "phenodata-mellifera", | ||
"enable": true, | ||
"hide": false, | ||
"iconColor": "#5794F2", | ||
"limit": 100, | ||
"name": "Flowering Forecast Müncheberg", | ||
"query": "flowering:type=forecast&station=müncheberg", | ||
"showIn": 0, | ||
"tags": [], | ||
"type": "tags" | ||
} | ||
] | ||
}, | ||
"editable": true, | ||
"gnetId": null, | ||
"graphTooltip": 0, | ||
"id": 2, | ||
"links": [], | ||
"panels": [ | ||
{ | ||
"aliasColors": {}, | ||
"bars": false, | ||
"dashLength": 10, | ||
"dashes": false, | ||
"datasource": "phenodata-mellifera", | ||
"fieldConfig": { | ||
"defaults": { | ||
"custom": {}, | ||
"links": [] | ||
}, | ||
"overrides": [] | ||
}, | ||
"fill": 1, | ||
"fillGradient": 0, | ||
"gridPos": { | ||
"h": 9, | ||
"w": 12, | ||
"x": 0, | ||
"y": 0 | ||
}, | ||
"hiddenSeries": false, | ||
"id": 2, | ||
"legend": { | ||
"avg": false, | ||
"current": false, | ||
"max": false, | ||
"min": false, | ||
"show": true, | ||
"total": false, | ||
"values": false | ||
}, | ||
"lines": true, | ||
"linewidth": 1, | ||
"nullPointMode": "null", | ||
"options": { | ||
"alertThreshold": true | ||
}, | ||
"percentage": false, | ||
"pluginVersion": "7.3.6", | ||
"pointradius": 2, | ||
"points": false, | ||
"renderer": "flot", | ||
"seriesOverrides": [], | ||
"spaceLength": 10, | ||
"stack": false, | ||
"steppedLine": false, | ||
"targets": [ | ||
{ | ||
"refId": "A", | ||
"target": "select metric", | ||
"type": "timeserie" | ||
} | ||
], | ||
"thresholds": [], | ||
"timeFrom": null, | ||
"timeRegions": [], | ||
"timeShift": null, | ||
"title": "Fruits for Apis mellifera in Müncheberg, Brandenburg, Germany", | ||
"tooltip": { | ||
"shared": true, | ||
"sort": 0, | ||
"value_type": "individual" | ||
}, | ||
"type": "graph", | ||
"xaxis": { | ||
"buckets": null, | ||
"mode": "time", | ||
"name": null, | ||
"show": true, | ||
"values": [] | ||
}, | ||
"yaxes": [ | ||
{ | ||
"format": "short", | ||
"label": null, | ||
"logBase": 1, | ||
"max": null, | ||
"min": null, | ||
"show": true | ||
}, | ||
{ | ||
"format": "short", | ||
"label": null, | ||
"logBase": 1, | ||
"max": null, | ||
"min": null, | ||
"show": true | ||
} | ||
], | ||
"yaxis": { | ||
"align": false, | ||
"alignLevel": null | ||
} | ||
} | ||
], | ||
"refresh": false, | ||
"schemaVersion": 26, | ||
"style": "dark", | ||
"tags": [], | ||
"templating": { | ||
"list": [] | ||
}, | ||
"time": { | ||
"from": "now-2y", | ||
"to": "now+1y" | ||
}, | ||
"timepicker": {}, | ||
"timezone": "", | ||
"title": "Fruits for Apis mellifera", | ||
"uid": "aoBz38xMy" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
{ | ||
"access": "proxy", | ||
"basicAuth": false, | ||
"basicAuthPassword": "", | ||
"basicAuthUser": "", | ||
"database": "", | ||
"isDefault": false, | ||
"jsonData": {}, | ||
"name": "phenodata-mellifera", | ||
"orgId": 1, | ||
"password": "", | ||
"readOnly": true, | ||
"secureJsonFields": {}, | ||
"type": "grafana-simple-json-datasource", | ||
"typeLogoUrl": "", | ||
"url": "http://host.docker.internal:3003", | ||
"user": "", | ||
"withCredentials": false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
""" | ||
Copyright 2020 Andreas Motl <andreas@hiveeyes.org> | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
""" | ||
import urllib.parse | ||
from datetime import datetime, timedelta | ||
|
||
import pandas as pd | ||
from cachetools import cached, TTLCache | ||
from phenodata.dwd.cdc import DwdCdcClient | ||
from phenodata.dwd.pheno import DwdPhenoDataHumanizer, DwdPhenoData | ||
from phenodata.ftp import FTPSession | ||
from phenodata.util import read_list | ||
|
||
from grafana_pandas_datasource import create_app | ||
from grafana_pandas_datasource.registry import data_generators as dg | ||
from grafana_pandas_datasource.service import pandas_component | ||
|
||
""" | ||
Demo for grafana-pandas-datasource. | ||
This is a demo program which generates flowering events for | ||
phenology species suitable as fruits for bees (Apis mellifera) | ||
as Grafana annotations. | ||
Setup:: | ||
pip install grafana-pandas-datasource phenodata>=0.10.0 cachetools | ||
To query the annotations, use ``<reader_name>:<query_string>``, e.g. | ||
- ``flowering:station=müncheberg`` | ||
""" | ||
|
||
|
||
def define_and_register_data(): | ||
|
||
# Sample annotation reader. | ||
def get_mellifera_flowering(query_string, ts_range): | ||
query = dict(urllib.parse.parse_qsl(query_string)) | ||
series = phenodata_mellifera( | ||
dataset="immediate", years=tuple([2019, 2020, 2021]), phases=tuple([5, 7]), | ||
options=tuple(query.items()) | ||
) | ||
return series | ||
|
||
# Register data generators. | ||
dg.add_annotation_reader("flowering", get_mellifera_flowering) | ||
|
||
|
||
@cached(cache=TTLCache(maxsize=65536, ttl=24 * 60 * 60)) | ||
def phenodata_mellifera(dataset: str, years: tuple[int], phases: tuple[str], options: tuple[tuple[str, str]]): | ||
|
||
options = dict(options) | ||
options["type"] = read_list(options.get("type")) or ["observations"] | ||
|
||
cdc_client = DwdCdcClient(ftp=FTPSession()) | ||
humanizer = DwdPhenoDataHumanizer(language="german", long_station=False, show_ids=False) | ||
client = DwdPhenoData(cdc=cdc_client, humanizer=humanizer, dataset=dataset) | ||
|
||
# Rewrite options. | ||
phenodata_options = { | ||
"partition": "recent", | ||
"year": years, | ||
"species": DwdPhenoData.load_preset("options", "species", "mellifera-de-primary"), | ||
"phase-id": phases, | ||
"station": read_list(options.get("station", [])), | ||
"humanize": True, | ||
} | ||
|
||
data_total = [] | ||
|
||
# Get observations | ||
if "observations" in options["type"]: | ||
data_past = client.get_observations(phenodata_options, humanize=phenodata_options['humanize']) | ||
data_total.append(data_past) | ||
|
||
if "forecast" in options["type"]: | ||
next_year = (datetime.today() + timedelta(days=365)).year | ||
data_future = client.get_forecast(phenodata_options, forecast_year=next_year, humanize=phenodata_options['humanize']) | ||
data_total.append(data_future) | ||
|
||
data = pd.concat(data_total) | ||
|
||
# Create Pandas Series from Dataframe. | ||
index = data.Datum.astype('datetime64') | ||
values = data.Spezies.str.cat(data.Phase, sep=" - ").str.cat(data.Station, sep=" - ") | ||
series = pd.Series(data=values.tolist(), index=index) | ||
series = series.sort_index(ascending=True) | ||
|
||
return series | ||
|
||
|
||
def main(): | ||
|
||
# Define and register data generators. | ||
define_and_register_data() | ||
|
||
# Create Flask application. | ||
app = create_app() | ||
|
||
# Register Pandas component. | ||
app.register_blueprint(pandas_component, url_prefix="/") | ||
|
||
# Invoke Flask application. | ||
app.run(host='127.0.0.1', port=3003, debug=True) | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
################################ | ||
Apis mellifera flowering example | ||
################################ | ||
This is a demo program which generates flowering events for | ||
phenology species suitable as fruits for bees (Apis mellifera) | ||
as Grafana annotations. | ||
|
||
.. figure:: https://user-images.githubusercontent.com/453543/103260962-fd1b8900-499f-11eb-8459-9ecaa6c55ac7.png | ||
|
||
Image: Flowering events for some species around Müncheberg, Brandenburg, Germany. | ||
|
||
|
||
Setup | ||
===== | ||
:: | ||
|
||
pip install grafana-pandas-datasource phenodata>=0.10.0 cachetools | ||
|
||
|
||
Acquire example files | ||
===================== | ||
:: | ||
|
||
export EXAMPLES_BASEURL=https://raw.githubusercontent.com/panodata/grafana-pandas-datasource/0.1.0/examples | ||
|
||
wget ${EXAMPLES_BASEURL}/phenodata-mellifera/demo.py \ | ||
--output-document=phenodata-mellifera-demo.py | ||
|
||
wget ${EXAMPLES_BASEURL}/phenodata-mellifera/datasource.json \ | ||
--output-document=phenodata-mellifera-datasource.json | ||
|
||
wget ${EXAMPLES_BASEURL}/phenodata-mellifera/dashboard.json \ | ||
--output-document=phenodata-mellifera-dashboard.json | ||
|
||
|
||
Invoke | ||
====== | ||
:: | ||
|
||
# Run Grafana. | ||
docker run --rm -it \ | ||
--publish=3000:3000 --volume="$(pwd)/var/lib/grafana":/var/lib/grafana \ | ||
--env='GF_SECURITY_ADMIN_PASSWORD=admin' --env='GF_INSTALL_PLUGINS=grafana-simple-json-datasource' \ | ||
grafana/grafana:7.3.6 | ||
|
||
# Run Grafana Pandas Datasource demo. | ||
python phenodata-mellifera-demo.py | ||
|
||
|
||
Configure | ||
========= | ||
.. note:: | ||
|
||
The host where the datasource service is running can be accessed from the | ||
Grafana Docker container using the hostname ``host.docker.internal``. | ||
|
||
You can have a quickstart by putting ``examples/phenodata-mellifera/datasource.json`` | ||
and ``examples/phenodata-mellifera/dashboard.json`` into Grafana:: | ||
|
||
# Login to Grafana. | ||
export GRAFANA_URL=http://localhost:3000 | ||
http --session=grafana ${GRAFANA_URL} --auth=admin:admin | ||
|
||
# Create datasource. | ||
cat phenodata-mellifera-datasource.json | \ | ||
http --session=grafana POST ${GRAFANA_URL}/api/datasources | ||
|
||
# Create dashboard. | ||
cat phenodata-mellifera-dashboard.json | \ | ||
http --session=grafana POST ${GRAFANA_URL}/api/dashboards/db | ||
|
||
open ${GRAFANA_URL} |