Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Toniof xxx wmts #48

Merged
merged 4 commits into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## Changes in 0.1.1 (in development)

* Scattermap can show background layers

## Changes in 0.1

Initial version.
Expand Down
239 changes: 237 additions & 2 deletions doors_dashboards/components/scattermap.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,20 @@
import matplotlib
import numpy as np
import os
from PIL import Image
import plotly.graph_objs as go
import random
import requests
from shapely.geometry import Point
from typing import Dict
from typing import List
from typing import Tuple

# import numpy as np
import base64
import matplotlib.pyplot as plt
import io


from doors_dashboards.components.constant import (
COLLECTION,
Expand All @@ -31,10 +38,210 @@

DEFAULT_COLOR_RANGE = "viridis"
DEFAULT_SELECTION_COLOR = "#CC0000"
SELECTION_COLOR = DEFAULT_SELECTION_COLOR
DEFAULT_SELECTION_SIZE = 17
HEADERS = {"accept": "application/json"}
SELECTION_COLOR = DEFAULT_SELECTION_COLOR
SELECTION_SIZE = DEFAULT_SELECTION_SIZE

TILE_VALUE_SETS = {
1: {
"lat_start_index": 0,
"lat_end_index": 0,
"lon_start_index": 2,
"lon_end_index": 2,
"resolution": 90,
},
2: {
"lat_start_index": 0,
"lat_end_index": 1,
"lon_start_index": 4,
"lon_end_index": 4,
"resolution": 45,
},
3: {
"lat_start_index": 1,
"lat_end_index": 2,
"lon_start_index": 9,
"lon_end_index": 9,
"resolution": 22.5,
},
4: {
"lat_start_index": 3,
"lat_end_index": 4,
"lon_start_index": 18,
"lon_end_index": 19,
"resolution": 11.25,
},
5: {
"lat_start_index": 7,
"lat_end_index": 8,
"lon_start_index": 36,
"lon_end_index": 39,
"resolution": 5.625,
},
6: {
"lat_start_index": 15,
"lat_end_index": 17,
"lon_start_index": 73,
"lon_end_index": 78,
"resolution": 2.8125,
},
7: {
"lat_start_index": 30,
"lat_end_index": 34,
"lon_start_index": 147,
"lon_end_index": 157,
"resolution": 1.40625,
},
}
TILE_ZOOM_LEVEL = 6

XCUBE_COLOR_BAR_URL = "https://doors.api.brockmann-consult.de/api/colorbars"


def get_color_bars():
response = requests.get(XCUBE_COLOR_BAR_URL, headers=HEADERS)
if response.status_code == 200:
return response.json()


XCUBE_COLOR_BARS = get_color_bars()


def get_color_map_image_stream(var_name: str):
bd = BACKGROUND_DEFINITONS.get(var_name)
cm_name = bd.get("colormap")
for color_bar_group in XCUBE_COLOR_BARS:
for color_bar in color_bar_group[2]:
if color_bar[0] == cm_name:
cbar_png_str = color_bar[1]
cbar_png_bytes = base64.b64decode(cbar_png_str)
stream = io.BytesIO(cbar_png_bytes)
return stream

XCUBE_SERVER_BASE_TILE_URL = "https://doors.api.brockmann-consult.de/api/tiles/{0}/{1}/{2}/{3}/{4}?vmin={5}&vmax={6}&cbar={7}&time={8}"
XCUBE_SERVER_BASE_TIME_URL = "https://doors.api.brockmann-consult.de/api/datasets/{0}/coords/time"

BACKGROUND_DEFINITONS = {
"chlorophyll": {
"vmin": 0,
"vmax": 40,
"colormap": "chl_DeM2",
"dataset_name": "cmems-chl-bs",
"variable_name": "CHL",
"title": "CHL [milligram m^-3]"
},
"salinity": {
"vmin": 10,
"vmax": 20,
"colormap": "haline",
"dataset_name": "cmcc-sal-bs",
"variable_name": "so",
"title": "Salinity [PSU]"
},
"sst": {
"vmin": 280,
"vmax": 302,
"colormap": "thermal",
"dataset_name": "cmems-sst-bs",
"variable_name": "analysed_sst",
"title": "Analysed SST [Kelvin]"
},
}


def get_time_coords(var_name: str) -> List[str]:
bd = BACKGROUND_DEFINITONS.get(var_name)
time_url = XCUBE_SERVER_BASE_TIME_URL.format(bd["dataset_name"])
response = requests.get(time_url, headers=HEADERS)
if response.status_code == 200:
return response.json().get("coordinates")


def get_last_time_coord(var_name: str) -> List[str]:
return get_time_coords(var_name)[-1]


def get_background_image_layers(var_name: str) -> List[Dict]:
bd = BACKGROUND_DEFINITONS.get(var_name)
image_layers = []
tvs = TILE_VALUE_SETS.get(TILE_ZOOM_LEVEL)
time = get_last_time_coord(var_name)
for lat_index in range(tvs["lat_start_index"], tvs["lat_end_index"] + 1):
lat_0 = 90 - (lat_index * tvs["resolution"])
lat_1 = lat_0 - tvs["resolution"]
for lon_index in range(tvs["lon_start_index"], tvs["lon_end_index"] + 1):
lon_0 = -180 + (lon_index * tvs["resolution"])
lon_1 = lon_0 + tvs["resolution"]
# time = "2024-06-29T00%3A00%3A00Z"
img = XCUBE_SERVER_BASE_TILE_URL.format(
bd["dataset_name"],
bd["variable_name"],
TILE_ZOOM_LEVEL,
lat_index,
lon_index,
bd["vmin"],
bd["vmax"],
bd["colormap"],
time
)
coordinates = [
[lon_0, lat_0],
[lon_1, lat_0],
[lon_1, lat_1],
[lon_0, lat_1],
]
image_layers.append(
{
"below": "traces",
"sourcetype": "image",
"source": img,
"coordinates": coordinates,
}
)
return image_layers


def get_annotations(var_name: str):
bd = BACKGROUND_DEFINITONS.get(var_name)
time = get_last_time_coord(var_name)
annotations = [
dict(
x=0.02,
y=-0.05,
xref="paper",
yref="paper",
text=bd["variable_name"],
showarrow=False,
font=dict(size=14),
),
dict(
x=0.02,
y=-0.1,
xref="paper",
yref="paper",
text=time,
showarrow=False,
font=dict(size=14),
)
]
vmin = bd["vmin"]
vmax = bd["vmax"]
vrange = (vmax - vmin) / 5
for i in range(6):
annotations.append(
dict(
x=0.2 + (i * 0.15),
y=-0.075,
xref="paper",
yref="paper",
text=vmin + (i * vrange),
showarrow=True,
font=dict(size=12),
)
)
return annotations


def get_center(lons: List[float], lats: List[float]) -> Tuple[float, float]:
center_lon = min(lons) + (max(lons) - min(lons)) / 2
Expand Down Expand Up @@ -66,6 +273,7 @@ def get(
marker_size = sub_config.get("marker_size", 10)
mapbox_style = sub_config.get("mapbox_style", "carto-positron")
selected_variable = sub_config.get("selected_variable", "")
background_variable = sub_config.get("background_variable", "")

figure = go.Figure()

Expand Down Expand Up @@ -127,7 +335,9 @@ def get(
)

center_lon, center_lat = get_center(all_lons, all_lats)

zoom = get_zoom_level(all_lons, all_lats, center_lon, center_lat)

mapbox_token = os.environ.get("MAPBOX_TOKEN")

mapbox = dict(
Expand All @@ -152,7 +362,32 @@ def get(
),
)

figure.update_layout(mapbox=mapbox)
if background_variable in list(BACKGROUND_DEFINITONS.keys()):
image_layers = get_background_image_layers(background_variable)
figure.update_layout(mapbox_layers=image_layers)

color_map_image_stream = get_color_map_image_stream(background_variable)
color_map_image = Image.open(color_map_image_stream)
figure.add_layout_image(
dict(
source=color_map_image,
xref="paper",
yref="paper",
x=0.2,
y=-0.075, # Positioning of the image
sizex=0.75,
sizey=0.5, # Size of the image
xanchor="left",
yanchor="top",
)
)
color_map_image_stream.close()
annotations = get_annotations(background_variable)
figure.update_layout(
annotations=annotations,
margin=dict(l=0, r=0, t=0, b=100), # Space for the color bar
)
figure.update_layout(mapbox=mapbox)

scattermap_graph = dcc.Graph(
id=sub_component_id, figure=figure, style={"height": "81.5vh"}
Expand Down