File size: 5,709 Bytes
64df5de
963ecfd
64df5de
 
 
963ecfd
64df5de
 
 
963ecfd
 
864777a
64df5de
 
 
 
42f5456
64df5de
 
 
 
963ecfd
64df5de
2c150e9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64df5de
 
 
 
 
 
 
 
42f5456
 
64df5de
 
 
963ecfd
64df5de
963ecfd
64df5de
963ecfd
7390946
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64df5de
963ecfd
64df5de
 
 
 
 
 
 
 
 
 
 
 
 
 
963ecfd
64df5de
 
963ecfd
64df5de
864777a
963ecfd
 
 
 
 
64df5de
 
 
 
 
 
864777a
 
 
 
963ecfd
 
 
64df5de
2c150e9
963ecfd
 
2c150e9
 
963ecfd
2c150e9
963ecfd
2c150e9
963ecfd
 
 
64df5de
 
 
 
 
864777a
64df5de
864777a
64df5de
864777a
64df5de
 
 
864777a
64df5de
864777a
64df5de
864777a
64df5de
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
from io import BytesIO
from pathlib import Path

import holoviews as hv
import numpy as np
import pandas as pd
import pyarrow.parquet as pq
from fsspec.parquet import open_parquet_file
from holoviews import opts
from PIL import Image

MAJOR_TOM_LOGO = "assets/major-tom-esa-logo.png"
MAJOR_TOM_PICTURE = (
    "https://upload.wikimedia.org/wikipedia/en/6/6d/Major_tom_space_oddity_video.JPG"
)
MAJOR_TOM_REF_URL = "https://huggingface.co/Major-TOM"
MAJOR_TOM_ARXIV_URL = "https://www.arxiv.org/abs/2402.12095"
PANEL_LOGO = "https://panel.holoviz.org/_static/logo_horizontal_light_theme.png"
PANEL_URL = "https://panel.holoviz.org"
DATASHADER_LOGO = "https://datashader.org/_static/logo_horizontal.svg"
DATASHADER_URL = "https://datashader.org/"
REPOSITORY = "Major-TOM"
DATASETS = ["Core-S2L2A", "Core-S2L1C"]
ESA_EASTING = 250668.73322714816
ESA_NORTHING = 6259216.653115547
META_DATA_COLUMNS = {
    "Coastal aerosol": "B01",
    "Blue": "B02",
    "Green": "B03",
    "Red": "B04",
    "Vegetation Blue": "B05",
    "Vegetation Green": "B06",
    "Vegetation Red": "B07",
    "NIR": "B08",
    "Narrow NIR": "B8A",
    "Water vapour": "B09",
    "SWIR, 1613.7": "B11",
    "SWIR, 2202.4": "B12",
    "Cloud Mask": "cloud_mask",
    "Thumbnail": "thumbnail",
}

DATA_PATH = Path(__file__).parent / "data"

DESCRIPTION = f"""\
## Dataset Explorer

This app provides a way of exploring samples present in the [MajorTOM-Core]({MAJOR_TOM_REF_URL}) dataset. It contains nearly every piece of Earth captured by ESA [Sentinel-2](https://sentinels.copernicus.eu/web/sentinel/missions/sentinel-2) satellite.

[Website]({MAJOR_TOM_REF_URL}), [arXiv Paper]({MAJOR_TOM_ARXIV_URL})

## Instructions

To find a sample, navigate on the map to a place of interest. Click the map to find a dataset sample at the location you clicked.

## Powered by

"""

MAJOR_TOM_LYRICS = """
Standing there alone, the ship is waiting
All systems are go, are you sure?
Control is not convinced, but the computer
Has the evidence, no need to abort
The countdown starts

Watching in a trance, the crew is certain
Nothing left to chance, all is working
Trying to relax up in the capsule
"Send me up a drink, " jokes **Major Tom**
The count goes on

Four, three, two, one

Earth below us, drifting, falling
Floating weightless, calling, calling home

Second stage is cut, we're now in orbit
Stabilizers up, running perfect
Starting to collect requested data
"What will it affect when all is done?"
Thinks **Major Tom**

Back at ground control, there is a problem
Go to rockets full, not responding
"Hello **Major Tom**, are you receiving?
Turn the thrusters on, we're standing by"
There's no reply

Four, three, two, one

Earth below us, drifting, falling
Floating weightless, calling, calling home

Across the stratosphere a final message
"Give my wife my love, " then nothing more
Far beneath the ship, the world is mourning
They don't realize he's alive
No one understands, but **Major Tom** sees
"Now the light commands, this is my home
I'm coming home"

Earth below us, drifting, falling
Floating weightless, coming home
Earth below us, drifting, falling
Floating weightless, coming home
Earth below us, drifting, falling
Floating weightless, coming, coming home

Home
Home
Home
Home
Home
"""

hv.extension("bokeh")

opts.defaults(
    # opts.Curve(xaxis=None, yaxis=None, show_grid=False, show_frame=False,
    #            color='orangered', framewise=True, width=100),
    opts.HLine(color="gray", line_width=1),
    # opts.Layout(shared_axes=False),
    opts.VLine(color="gray", line_width=1),
)


def _meta_data_url(dataset="Core-S2L2A", repository=REPOSITORY):
    return f"https://huggingface.co/datasets/{repository}/{dataset}/resolve/main/metadata.parquet"


def _meta_data_path(dataset="Core-S2L2A", repository=REPOSITORY):
    DATA_PATH.mkdir(parents=True, exist_ok=True)
    return DATA_PATH / f"{dataset}_metadata.parquet"


def get_meta_data(dataset="Core-S2L2A", repository=REPOSITORY):
    print(f"Loading {dataset}")
    path = _meta_data_path(dataset=dataset)
    if not path.exists():
        data = pd.read_parquet(_meta_data_url(dataset=dataset))
        data.to_parquet(path)
    data = pd.read_parquet(path)

    data["centre_easting"], data["centre_northing"] = (
        hv.util.transform.lon_lat_to_easting_northing(
            data["centre_lon"], data["centre_lat"]
        )
    )
    # Optimize Performance
    data["timestamp"] = pd.to_datetime(data["timestamp"])
    numeric_cols = ["cloud_cover", "nodata", "centre_lat", "centre_lon"]
    data[numeric_cols] = data[numeric_cols].astype("float32")

    return data


def get_image(row, column="thumbnail"):
    parquet_url = row["parquet_url"]
    parquet_row = row["parquet_row"]
    print(parquet_url, parquet_row, column)
    with open_parquet_file(parquet_url, columns=[column]) as f:
        with pq.ParquetFile(f) as pf:
            first_row_group = pf.read_row_group(parquet_row, columns=[column])

    stream = BytesIO(first_row_group[column][0].as_py())
    image = Image.open(stream)
    return image


def euclidean_distance(x, y, target_x, target_y):
    return np.sqrt((x - target_x) ** 2 + (y - target_y) ** 2)


def get_closest_row(data, target_easting, target_northing):
    distance = euclidean_distance(
        data["centre_easting"], data["centre_northing"], target_easting, target_northing
    )
    closest_row = data.loc[distance.idxmin()]
    return closest_row


def get_closest_rows(data, target_easting, target_northing):
    distance = euclidean_distance(
        data["centre_easting"], data["centre_northing"], target_easting, target_northing
    )
    closest_rows = data[distance == distance.min()]
    return closest_rows