Spaces:
Runtime error
Runtime error
Commit
·
c721171
1
Parent(s):
07fcfdd
Added GeoTIFF support and utilities page
Browse files
pyproject.toml
CHANGED
|
@@ -18,7 +18,8 @@ dependencies = [
|
|
| 18 |
"scipy",
|
| 19 |
"pandas",
|
| 20 |
"networkx",
|
| 21 |
-
"openpyxl"
|
|
|
|
| 22 |
]
|
| 23 |
|
| 24 |
[tool.hatch.version]
|
|
|
|
| 18 |
"scipy",
|
| 19 |
"pandas",
|
| 20 |
"networkx",
|
| 21 |
+
"openpyxl",
|
| 22 |
+
"rasterio"
|
| 23 |
]
|
| 24 |
|
| 25 |
[tool.hatch.version]
|
requirements.txt
CHANGED
|
@@ -6,4 +6,5 @@ lorem_text
|
|
| 6 |
matplotlib
|
| 7 |
psycopg2-binary
|
| 8 |
scipy
|
| 9 |
-
pandas
|
|
|
|
|
|
| 6 |
matplotlib
|
| 7 |
psycopg2-binary
|
| 8 |
scipy
|
| 9 |
+
pandas
|
| 10 |
+
rasterio
|
tomorrowcities/content/articles/data_formats.md
CHANGED
|
@@ -49,5 +49,8 @@ where
|
|
| 49 |
* **residents (integer)** stores the number of individual live in the building.
|
| 50 |
* **expStr (string)**
|
| 51 |
|
|
|
|
|
|
|
|
|
|
| 52 |
|
| 53 |
|
|
|
|
| 49 |
* **residents (integer)** stores the number of individual live in the building.
|
| 50 |
* **expStr (string)**
|
| 51 |
|
| 52 |
+
### Intensity Measures
|
| 53 |
+
Whether it is flood, debris or earthquake, every hazard map should contain at least two properties: a point geometry and intensity measure denotes by 'im'. The data can be provided via GeoTIFF or GeoJSON format. TIFF files should contain CRS
|
| 54 |
+
information so that the engine could map the coordinates to a common CRS to conduct calculations.
|
| 55 |
|
| 56 |
|
tomorrowcities/content/articles/welcome.md
CHANGED
|
@@ -15,6 +15,13 @@ category:
|
|
| 15 |
TCDSE is a web application designed to conduct computational tasks to generate information needed for decision mechanisms in designing future cities. The web application, which will be referred as TCDSE for short, contains a computational engine capable of executing several hazard scenarios on different exposure datasets and infrastructures.
|
| 16 |
|
| 17 |
## What is New?
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
* Info box is added next to the map to see overall information and building/landuse details
|
| 19 |
when clicked.
|
| 20 |
* Implementation Capacity Score is added. If medium or low is selected, then building-level metrics is increased by 25% and 50%, respectively. If high is selected, there is no change in the metrics.
|
|
|
|
| 15 |
TCDSE is a web application designed to conduct computational tasks to generate information needed for decision mechanisms in designing future cities. The web application, which will be referred as TCDSE for short, contains a computational engine capable of executing several hazard scenarios on different exposure datasets and infrastructures.
|
| 16 |
|
| 17 |
## What is New?
|
| 18 |
+
* basemap is changed to ESri.WorldImagery to see the landscapes especially rivers.
|
| 19 |
+
* utilities page is added.
|
| 20 |
+
* Excel to GeoJSON converted is added to utilities page.
|
| 21 |
+
* GeoTIFF support is added.
|
| 22 |
+
* When an intensity layer is added via GeoTIFF format, only the non-zero intensity measure are retained by the engine.
|
| 23 |
+
* In map visualization of intensity layer, only the largest 500k points are displayed to render the map faster.
|
| 24 |
+
* rasterio.transform.xy function is replaced with a faster local implementation.
|
| 25 |
* Info box is added next to the map to see overall information and building/landuse details
|
| 26 |
when clicked.
|
| 27 |
* Implementation Capacity Score is added. If medium or low is selected, then building-level metrics is increased by 25% and 50%, respectively. If high is selected, there is no change in the metrics.
|
tomorrowcities/pages/__init__.py
CHANGED
|
@@ -5,7 +5,7 @@ import dataclasses
|
|
| 5 |
|
| 6 |
from ..data import articles
|
| 7 |
|
| 8 |
-
route_order = ["/", "docs","engine","settings","account"]
|
| 9 |
|
| 10 |
def check_auth(route, children):
|
| 11 |
# This can be replaced by a custom function that checks if the user is
|
|
@@ -13,7 +13,7 @@ def check_auth(route, children):
|
|
| 13 |
|
| 14 |
# routes that are public or only for admin
|
| 15 |
# the rest only requires login
|
| 16 |
-
public_paths = ["/","docs","engine","account"]
|
| 17 |
admin_paths = ["settings"]
|
| 18 |
|
| 19 |
|
|
|
|
| 5 |
|
| 6 |
from ..data import articles
|
| 7 |
|
| 8 |
+
route_order = ["/", "docs","engine","utilities","settings","account"]
|
| 9 |
|
| 10 |
def check_auth(route, children):
|
| 11 |
# This can be replaced by a custom function that checks if the user is
|
|
|
|
| 13 |
|
| 14 |
# routes that are public or only for admin
|
| 15 |
# the rest only requires login
|
| 16 |
+
public_paths = ["/","docs","engine","utilities","account"]
|
| 17 |
admin_paths = ["settings"]
|
| 18 |
|
| 19 |
|
tomorrowcities/pages/engine.py
CHANGED
|
@@ -10,6 +10,9 @@ from typing import Tuple, Optional
|
|
| 10 |
import ipyleaflet
|
| 11 |
from ipyleaflet import AwesomeIcon, Marker
|
| 12 |
import numpy as np
|
|
|
|
|
|
|
|
|
|
| 13 |
import logging, sys
|
| 14 |
#logging.basicConfig(stream=sys.stderr, level=logging.INFO)
|
| 15 |
|
|
@@ -96,9 +99,7 @@ layers = solara.reactive({
|
|
| 96 |
'force_render': solara.reactive(False),
|
| 97 |
'visible': solara.reactive(False),
|
| 98 |
'extra_cols': {'ds': 0, 'is_damaged': False, 'is_operational': True},
|
| 99 |
-
'cols_required': set(['geometry', '
|
| 100 |
-
'node_id', 'x_coord', 'y_coord', 'pwr_plant', 'serv_area', 'n_bldgs',
|
| 101 |
-
'income', 'eq_vuln']),
|
| 102 |
'cols': set(['geometry', 'fltytype', 'strctype', 'utilfcltyc', 'indpnode', 'guid',
|
| 103 |
'node_id', 'x_coord', 'y_coord', 'pwr_plant', 'serv_area', 'n_bldgs',
|
| 104 |
'income', 'eq_vuln'])},
|
|
@@ -110,8 +111,7 @@ layers = solara.reactive({
|
|
| 110 |
'force_render': solara.reactive(False),
|
| 111 |
'visible': solara.reactive(False),
|
| 112 |
'extra_cols': {},
|
| 113 |
-
'cols_required': set(['
|
| 114 |
-
'geometry', 'to_node', 'length']),
|
| 115 |
'cols': set(['from_node', 'direction', 'pipetype', 'edge_id', 'guid', 'capacity',
|
| 116 |
'geometry', 'to_node', 'length'])},
|
| 117 |
'power fragility': {
|
|
@@ -261,7 +261,9 @@ def create_map_layer(df, name):
|
|
| 261 |
return existing_map_layer
|
| 262 |
|
| 263 |
if name == "intensity":
|
| 264 |
-
|
|
|
|
|
|
|
| 265 |
map_layer = ipyleaflet.Heatmap(locations=locs, radius = 10)
|
| 266 |
elif name == "landuse":
|
| 267 |
map_layer = ipyleaflet.GeoJSON(data = json.loads(df.to_json()),
|
|
@@ -282,7 +284,7 @@ def create_map_layer(df, name):
|
|
| 282 |
x = node.geometry.x
|
| 283 |
y = node.geometry.y
|
| 284 |
marker_color = 'blue' if node['is_operational'] else 'red'
|
| 285 |
-
icon_name = 'fa-industry' if node['pwr_plant'] else 'bolt'
|
| 286 |
icon_color = 'black'
|
| 287 |
marker = Marker(icon=AwesomeIcon(
|
| 288 |
name=icon_name,
|
|
@@ -302,6 +304,52 @@ def create_map_layer(df, name):
|
|
| 302 |
layers.value['layers'][name]['force_render'].set(False)
|
| 303 |
return map_layer
|
| 304 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 305 |
@solara.component
|
| 306 |
def MetricWidget(name, description, value, max_value, render_count):
|
| 307 |
value, set_value = solara.use_state_or_update(value)
|
|
@@ -342,6 +390,8 @@ def import_data(fileinfo: solara.components.file_drop.FileInfo):
|
|
| 342 |
extension = fileinfo['name'].split('.')[-1]
|
| 343 |
if extension == 'xlsx':
|
| 344 |
df = pd.read_excel(data)
|
|
|
|
|
|
|
| 345 |
else:
|
| 346 |
json_string = data.decode('utf-8')
|
| 347 |
json_data = json.loads(json_string)
|
|
@@ -491,7 +541,7 @@ def MapViewer():
|
|
| 491 |
zoom, set_zoom = solara.use_state(default_zoom)
|
| 492 |
#center, set_center = solara.use_state(default_center)
|
| 493 |
|
| 494 |
-
base_map = ipyleaflet.basemaps["
|
| 495 |
base_layer = ipyleaflet.TileLayer.element(url=base_map.build_url())
|
| 496 |
map_layers = [base_layer]
|
| 497 |
|
|
|
|
| 10 |
import ipyleaflet
|
| 11 |
from ipyleaflet import AwesomeIcon, Marker
|
| 12 |
import numpy as np
|
| 13 |
+
import rasterio
|
| 14 |
+
from rasterio.warp import calculate_default_transform, reproject, Resampling
|
| 15 |
+
import io
|
| 16 |
import logging, sys
|
| 17 |
#logging.basicConfig(stream=sys.stderr, level=logging.INFO)
|
| 18 |
|
|
|
|
| 99 |
'force_render': solara.reactive(False),
|
| 100 |
'visible': solara.reactive(False),
|
| 101 |
'extra_cols': {'ds': 0, 'is_damaged': False, 'is_operational': True},
|
| 102 |
+
'cols_required': set(['geometry', 'node_id', 'pwr_plant', 'n_bldgs', 'eq_vuln']),
|
|
|
|
|
|
|
| 103 |
'cols': set(['geometry', 'fltytype', 'strctype', 'utilfcltyc', 'indpnode', 'guid',
|
| 104 |
'node_id', 'x_coord', 'y_coord', 'pwr_plant', 'serv_area', 'n_bldgs',
|
| 105 |
'income', 'eq_vuln'])},
|
|
|
|
| 111 |
'force_render': solara.reactive(False),
|
| 112 |
'visible': solara.reactive(False),
|
| 113 |
'extra_cols': {},
|
| 114 |
+
'cols_required': set(['geometry','from_node','to_node', 'edge_id']),
|
|
|
|
| 115 |
'cols': set(['from_node', 'direction', 'pipetype', 'edge_id', 'guid', 'capacity',
|
| 116 |
'geometry', 'to_node', 'length'])},
|
| 117 |
'power fragility': {
|
|
|
|
| 261 |
return existing_map_layer
|
| 262 |
|
| 263 |
if name == "intensity":
|
| 264 |
+
# Take the largest 500_000 values to display
|
| 265 |
+
df_limited = df.sort_values(by='im',ascending=False).head(500_000)
|
| 266 |
+
locs = np.array([df_limited.geometry.y.to_list(), df_limited.geometry.x.to_list(), df_limited.im.to_list()]).transpose().tolist()
|
| 267 |
map_layer = ipyleaflet.Heatmap(locations=locs, radius = 10)
|
| 268 |
elif name == "landuse":
|
| 269 |
map_layer = ipyleaflet.GeoJSON(data = json.loads(df.to_json()),
|
|
|
|
| 284 |
x = node.geometry.x
|
| 285 |
y = node.geometry.y
|
| 286 |
marker_color = 'blue' if node['is_operational'] else 'red'
|
| 287 |
+
icon_name = 'fa-industry' if node['pwr_plant'] == 1 else 'bolt'
|
| 288 |
icon_color = 'black'
|
| 289 |
marker = Marker(icon=AwesomeIcon(
|
| 290 |
name=icon_name,
|
|
|
|
| 304 |
layers.value['layers'][name]['force_render'].set(False)
|
| 305 |
return map_layer
|
| 306 |
|
| 307 |
+
def fast_transform_xy(T,x,y):
|
| 308 |
+
TI = rasterio.transform.IDENTITY.translation(0.5, 0.5)
|
| 309 |
+
TI_mat = np.array([[TI[0],TI[1],TI[2]],[TI[3],TI[4],TI[5]]])
|
| 310 |
+
T_mat = np.array([[T[0],T[1],T[2]],[T[3],T[4],T[5]]])
|
| 311 |
+
n = len(x)
|
| 312 |
+
first_input = np.ones((3,n))
|
| 313 |
+
first_input[0,:] = x
|
| 314 |
+
first_input[1,:] = y
|
| 315 |
+
first_pass = np.dot(TI_mat, first_input)
|
| 316 |
+
second_inp = np.concatenate([first_pass[[1]],first_pass[[0]],first_input[[2]]])
|
| 317 |
+
second_pass = np.dot(T_mat, second_inp)
|
| 318 |
+
return second_pass[0], second_pass[1]
|
| 319 |
+
|
| 320 |
+
def read_tiff(file_bytes):
|
| 321 |
+
byte_io = io.BytesIO(file_bytes)
|
| 322 |
+
with rasterio.open(byte_io) as src:
|
| 323 |
+
ims = src.read()
|
| 324 |
+
|
| 325 |
+
current_crs = src.crs
|
| 326 |
+
target_crs = 'EPSG:4326'
|
| 327 |
+
transform, width, height = calculate_default_transform(current_crs, target_crs, src.width, src.height, *src.bounds)
|
| 328 |
+
ims_transformed = np.zeros((height, width))
|
| 329 |
+
|
| 330 |
+
print('start reproject ..........')
|
| 331 |
+
reproject(
|
| 332 |
+
source=ims[0],
|
| 333 |
+
destination=ims_transformed,
|
| 334 |
+
src_transform=src.transform,
|
| 335 |
+
src_crs=current_crs,
|
| 336 |
+
dst_transform=transform,
|
| 337 |
+
dst_crs=target_crs,
|
| 338 |
+
resampling=Resampling.nearest)
|
| 339 |
+
|
| 340 |
+
|
| 341 |
+
lon_pos, lat_pos = np.meshgrid(range(width),range(height))
|
| 342 |
+
print('start transform ..........')
|
| 343 |
+
#lon, lat = rasterio.transform.xy(transform,lat_pos.flatten(),lon_pos.flatten())
|
| 344 |
+
lon, lat = fast_transform_xy(transform,lat_pos.flatten(),lon_pos.flatten())
|
| 345 |
+
print('start dataframe ..........')
|
| 346 |
+
gdf = gpd.GeoDataFrame(ims_transformed.flatten(),
|
| 347 |
+
geometry = gpd.points_from_xy(lon, lat, crs="EPSG:4326"))
|
| 348 |
+
gdf = gdf.rename(columns={0:'im'})
|
| 349 |
+
# return only the non-zero intensity measures
|
| 350 |
+
return gdf[gdf['im'] > 0]
|
| 351 |
+
#return gdf.sort_values(by='im',ascending=False).head(10000)
|
| 352 |
+
|
| 353 |
@solara.component
|
| 354 |
def MetricWidget(name, description, value, max_value, render_count):
|
| 355 |
value, set_value = solara.use_state_or_update(value)
|
|
|
|
| 390 |
extension = fileinfo['name'].split('.')[-1]
|
| 391 |
if extension == 'xlsx':
|
| 392 |
df = pd.read_excel(data)
|
| 393 |
+
elif extension in ['tiff','tif']:
|
| 394 |
+
df = read_tiff(data)
|
| 395 |
else:
|
| 396 |
json_string = data.decode('utf-8')
|
| 397 |
json_data = json.loads(json_string)
|
|
|
|
| 541 |
zoom, set_zoom = solara.use_state(default_zoom)
|
| 542 |
#center, set_center = solara.use_state(default_center)
|
| 543 |
|
| 544 |
+
base_map = ipyleaflet.basemaps["Esri"]["WorldImagery"]
|
| 545 |
base_layer = ipyleaflet.TileLayer.element(url=base_map.build_url())
|
| 546 |
map_layers = [base_layer]
|
| 547 |
|
tomorrowcities/pages/utilities.py
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import solara
|
| 2 |
+
import time
|
| 3 |
+
import random
|
| 4 |
+
import json
|
| 5 |
+
import pandas as pd
|
| 6 |
+
import os
|
| 7 |
+
os.environ['USE_PYGEOS'] = '0'
|
| 8 |
+
import geopandas as gpd
|
| 9 |
+
from typing import Tuple, Optional
|
| 10 |
+
import ipyleaflet
|
| 11 |
+
from ipyleaflet import AwesomeIcon, Marker
|
| 12 |
+
import numpy as np
|
| 13 |
+
import logging, sys
|
| 14 |
+
#logging.basicConfig(stream=sys.stderr, level=logging.INFO)
|
| 15 |
+
|
| 16 |
+
from ..backend.engine import compute, compute_power_infra, calculate_metrics
|
| 17 |
+
|
| 18 |
+
app_data = solara.reactive({'df': solara.reactive(None),
|
| 19 |
+
'gdf': solara.reactive(None),
|
| 20 |
+
'selected_columns': solara.reactive([]),
|
| 21 |
+
'lat': solara.reactive(None),
|
| 22 |
+
'lon': solara.reactive(None),
|
| 23 |
+
'im': solara.reactive(None)})
|
| 24 |
+
|
| 25 |
+
def import_data(fileinfo: solara.components.file_drop.FileInfo):
|
| 26 |
+
data = fileinfo['data']
|
| 27 |
+
extension = fileinfo['name'].split('.')[-1]
|
| 28 |
+
if extension == 'xlsx':
|
| 29 |
+
df = pd.read_excel(data)
|
| 30 |
+
elif extension == 'csv':
|
| 31 |
+
df = pd.read_csv(data)
|
| 32 |
+
else:
|
| 33 |
+
json_string = data.decode('utf-8')
|
| 34 |
+
json_data = json.loads(json_string)
|
| 35 |
+
if "features" in json_data.keys():
|
| 36 |
+
df = gpd.GeoDataFrame.from_features(json_data['features'])
|
| 37 |
+
else:
|
| 38 |
+
df = pd.read_json(json_string)
|
| 39 |
+
|
| 40 |
+
df.columns = df.columns.str.lower()
|
| 41 |
+
|
| 42 |
+
return df
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
@solara.component
|
| 46 |
+
def FileDropZone():
|
| 47 |
+
total_progress, set_total_progress = solara.use_state(-1)
|
| 48 |
+
fileinfo, set_fileinfo = solara.use_state(None)
|
| 49 |
+
result, set_result = solara.use_state(solara.Result(True))
|
| 50 |
+
|
| 51 |
+
def load():
|
| 52 |
+
print('loading')
|
| 53 |
+
if fileinfo is not None:
|
| 54 |
+
print('processing file')
|
| 55 |
+
df = import_data(fileinfo)
|
| 56 |
+
print('importing done')
|
| 57 |
+
if df is not None:
|
| 58 |
+
app_data.value['df'].set(df)
|
| 59 |
+
else:
|
| 60 |
+
return False
|
| 61 |
+
return True
|
| 62 |
+
|
| 63 |
+
def progress(x):
|
| 64 |
+
set_total_progress(x)
|
| 65 |
+
|
| 66 |
+
def on_file_deneme(f):
|
| 67 |
+
set_fileinfo(f)
|
| 68 |
+
|
| 69 |
+
result = solara.use_thread(load, dependencies=[fileinfo])
|
| 70 |
+
|
| 71 |
+
solara.Markdown("Step1: Drag and drop your Excel file to the below area.")
|
| 72 |
+
solara.FileDrop(on_total_progress=progress,
|
| 73 |
+
on_file=on_file_deneme,
|
| 74 |
+
lazy=False)
|
| 75 |
+
if total_progress > -1 and total_progress < 100:
|
| 76 |
+
solara.Text(f"Uploading {total_progress}%")
|
| 77 |
+
solara.ProgressLinear(value=total_progress)
|
| 78 |
+
else:
|
| 79 |
+
if result.state == solara.ResultState.FINISHED:
|
| 80 |
+
if result.value:
|
| 81 |
+
solara.Text("Spacer", style={'visibility':'hidden'})
|
| 82 |
+
else:
|
| 83 |
+
solara.Text("Unrecognized file")
|
| 84 |
+
solara.ProgressLinear(value=False)
|
| 85 |
+
elif result.state == solara.ResultState.INITIAL:
|
| 86 |
+
solara.Text("Spacer", style={'visibility':'hidden'})
|
| 87 |
+
solara.ProgressLinear(value=False)
|
| 88 |
+
elif result.state == solara.ResultState.ERROR:
|
| 89 |
+
solara.Text(f'{result.error}')
|
| 90 |
+
solara.ProgressLinear(value=False)
|
| 91 |
+
else:
|
| 92 |
+
solara.Text("Reading the contents")
|
| 93 |
+
solara.ProgressLinear(value=True)
|
| 94 |
+
|
| 95 |
+
@solara.component
|
| 96 |
+
def DataframeDisplayer():
|
| 97 |
+
if app_data.value['df'].value is not None:
|
| 98 |
+
solara.DataFrame(app_data.value['df'].value)
|
| 99 |
+
|
| 100 |
+
@solara.component
|
| 101 |
+
def FieldSelector():
|
| 102 |
+
solara.Markdown("Step 2: Select the field names")
|
| 103 |
+
if app_data.value['df'].value is not None:
|
| 104 |
+
solara.Text("lat")
|
| 105 |
+
solara.ToggleButtonsSingle(value=app_data.value['lat'].value, values=list(app_data.value['df'].value.columns), on_value=app_data.value['lat'].set)
|
| 106 |
+
solara.Text("lon")
|
| 107 |
+
solara.ToggleButtonsSingle(value=app_data.value['lon'].value, values=list(app_data.value['df'].value.columns),on_value=app_data.value['lon'].set)
|
| 108 |
+
solara.Text("im")
|
| 109 |
+
solara.ToggleButtonsSingle(value=app_data.value['im'].value, values=list(app_data.value['df'].value.columns),on_value=app_data.value['im'].set)
|
| 110 |
+
|
| 111 |
+
@solara.component
|
| 112 |
+
def Downloader():
|
| 113 |
+
error_msg, set_error_msg = solara.use_state(None)
|
| 114 |
+
success_msg, set_success_msg = solara.use_state(None)
|
| 115 |
+
def generate():
|
| 116 |
+
set_error_msg(None)
|
| 117 |
+
set_success_msg(None)
|
| 118 |
+
if app_data.value['df'].value is not None:
|
| 119 |
+
if app_data.value['lat'].value is not None:
|
| 120 |
+
if app_data.value['lon'].value is not None:
|
| 121 |
+
if app_data.value['im'].value is not None:
|
| 122 |
+
try:
|
| 123 |
+
lat = app_data.value['lat'].value
|
| 124 |
+
lon = app_data.value['lon'].value
|
| 125 |
+
im = app_data.value['im'].value
|
| 126 |
+
df_conv = app_data.value['df'].value[[lat,lon,im]]
|
| 127 |
+
df_conv = df_conv.rename(columns={lat:'lat',lon:'lon',im:'im'})
|
| 128 |
+
gdf = gpd.GeoDataFrame(df_conv[['im']],
|
| 129 |
+
geometry = gpd.points_from_xy(df_conv[lon], df_conv[lat], crs="EPSG:4326"))
|
| 130 |
+
app_data.value['gdf'].set(gdf)
|
| 131 |
+
set_success_msg("Your file is ready")
|
| 132 |
+
set_error_msg(None)
|
| 133 |
+
except Exception as e:
|
| 134 |
+
app_data.value['gdf'].set(None)
|
| 135 |
+
set_error_msg(repr(e))
|
| 136 |
+
set_success_msg(None)
|
| 137 |
+
|
| 138 |
+
solara.Markdown("Step 3: Clict to generate GeoJSON")
|
| 139 |
+
solara.Button("Generate GeoJSON", icon_name="mdi-cloud-download-outline", color="primary", on_click=generate)
|
| 140 |
+
if error_msg is not None:
|
| 141 |
+
solara.Error(error_msg)
|
| 142 |
+
if success_msg is not None:
|
| 143 |
+
solara.Success(success_msg)
|
| 144 |
+
if app_data.value['gdf'].value is not None:
|
| 145 |
+
file_object = app_data.value['gdf'].value .to_json()
|
| 146 |
+
with solara.FileDownload(file_object, "intensity_blabla.geojson", mime_type="application/geo+json"):
|
| 147 |
+
solara.Button("Click to Downlaod genereated GeoJSON", icon_name="mdi-cloud-download-outline", color="primary")
|
| 148 |
+
@solara.component
|
| 149 |
+
def Utilities():
|
| 150 |
+
with solara.Columns([30,80]):
|
| 151 |
+
FileDropZone()
|
| 152 |
+
FieldSelector()
|
| 153 |
+
Downloader()
|
| 154 |
+
DataframeDisplayer()
|
| 155 |
+
|
| 156 |
+
|
| 157 |
+
@solara.component
|
| 158 |
+
def Page(name: Optional[str] = None, page: int = 0, page_size=100):
|
| 159 |
+
css = """
|
| 160 |
+
.v-input {
|
| 161 |
+
height: 10px;
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
.v-btn-toggle:not(.v-btn-toggle--dense) .v-btn.v-btn.v-size--default {
|
| 165 |
+
height: 24px;
|
| 166 |
+
min-height: 0;
|
| 167 |
+
min-width: 24px;
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
"""
|
| 171 |
+
solara.Style(value=css)
|
| 172 |
+
solara.Title("TCDSE » Engine")
|
| 173 |
+
|
| 174 |
+
Utilities()
|