Spaces:
Runtime error
Runtime error
Merge pull request #93 from TomorrowsCities/feature_persistence_to_browser_refresh
Browse files- tomorrowcities/pages/engine.py +72 -21
tomorrowcities/pages/engine.py
CHANGED
|
@@ -39,7 +39,7 @@ tally_counter = solara.reactive(0)
|
|
| 39 |
tally_filter = solara.reactive(None)
|
| 40 |
building_filter = solara.reactive(None)
|
| 41 |
landuse_filter = solara.reactive(None)
|
| 42 |
-
|
| 43 |
def create_new_app_state():
|
| 44 |
return solara.reactive({
|
| 45 |
'infra': solara.reactive(["building"]),
|
|
@@ -235,7 +235,7 @@ def create_new_app_state():
|
|
| 235 |
'attributes': [set(['vuln_string', 'med_slight', 'med_moderate', 'med_extensive', 'med_complete',
|
| 236 |
'dispersion'])]}
|
| 237 |
},
|
| 238 |
-
'center': solara.reactive(
|
| 239 |
'selected_layer' : solara.reactive(None),
|
| 240 |
'render_count': solara.reactive(0),
|
| 241 |
'bounds': solara.reactive(None),
|
|
@@ -341,7 +341,55 @@ def load_from_state(source_dict):
|
|
| 341 |
assign_nested_value(layers.value, keys, solara.reactive(src_value))
|
| 342 |
else:
|
| 343 |
assign_nested_value(layers.value, keys, src_value)
|
| 344 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 345 |
def create_metadata(data):
|
| 346 |
m = dict()
|
| 347 |
m['hazard'] = data['hazard']
|
|
@@ -896,13 +944,13 @@ def FilterPanel():
|
|
| 896 |
# filters[layer_name], _ = solara.use_cross_filter(id(df), "dataframe")
|
| 897 |
|
| 898 |
building = layers.value['layers']['building']['df'].value
|
|
|
|
| 899 |
if building is not None:
|
| 900 |
with solara.Row(): #spacer
|
| 901 |
solara.Markdown('''<h5 style=""></h5>''')
|
| 902 |
btn = solara.Button("BUILDING FILTERS")
|
| 903 |
with solara.Column(align="stretch"):
|
| 904 |
with solara.lab.Menu(activator=btn, close_on_content_click=False, style={"width":"35vh", "align":"stretch"}): #"height":"60vh"
|
| 905 |
-
building_filter.value, _ = solara.use_cross_filter(id(building), "building_filter")
|
| 906 |
solara.CrossFilterReport(building)
|
| 907 |
solara.CrossFilterSelect(building, "ds", multiple=True)
|
| 908 |
solara.CrossFilterSelect(building, "specialfac", multiple=True)
|
|
@@ -913,29 +961,30 @@ def FilterPanel():
|
|
| 913 |
solara.CrossFilterSelect(building, "code_level", multiple=True)
|
| 914 |
solara.CrossFilterSelect(building, "material", multiple=True)
|
| 915 |
solara.CrossFilterSelect(building, "zoneid", multiple=True)
|
| 916 |
-
|
| 917 |
landuse = layers.value['layers']['landuse']['df'].value
|
|
|
|
| 918 |
if landuse is not None:
|
| 919 |
with solara.Row(): #spacer
|
| 920 |
solara.Markdown('''<h5 style=""></h5>''')
|
| 921 |
btn = solara.Button("LANDUSE FILTERS")
|
| 922 |
with solara.Column(align="stretch"):
|
| 923 |
with solara.lab.Menu(activator=btn, close_on_content_click=False, style={"width":"35vh", "align":"stretch"}): #"height":"60vh"
|
| 924 |
-
landuse_filter.value, _ = solara.use_cross_filter(id(landuse), "landuse_filter")
|
| 925 |
solara.CrossFilterReport(landuse)
|
| 926 |
solara.CrossFilterSelect(landuse, "luf", multiple=True)
|
| 927 |
solara.CrossFilterSelect(landuse, "avgincome", multiple=True)
|
| 928 |
|
|
|
|
| 929 |
tc = tally_counter.value
|
| 930 |
print('tally_counter', tc)
|
| 931 |
tally_minimal = read_from_session_storage('tally_minimal')
|
|
|
|
| 932 |
if tally_minimal is not None:
|
| 933 |
with solara.Row(): #spacer
|
| 934 |
solara.Markdown('''<h5 style=""></h5>''')
|
| 935 |
btn = solara.Button("METRIC FILTERS")
|
| 936 |
with solara.Column(align="stretch"):
|
| 937 |
with solara.lab.Menu(activator=btn, close_on_content_click=False, style={"width":"35vh", "align":"stretch"}): #"height":"60vh"
|
| 938 |
-
tally_filter.value, _ = solara.use_cross_filter(id(tally_minimal), "tally_filter")
|
| 939 |
solara.CrossFilterReport(tally_minimal)
|
| 940 |
for col in layers.value['tally_filter_cols']:
|
| 941 |
solara.CrossFilterSelect(tally_minimal, col, multiple=True)
|
|
@@ -989,14 +1038,15 @@ def generate_metrics_local():
|
|
| 989 |
metrics = {name: {'value':0, 'max_value':0, 'desc': metric['desc']} for name, metric in layers.value['metrics'].items()}
|
| 990 |
|
| 991 |
tally_geo = read_from_session_storage('tally_geo')
|
|
|
|
|
|
|
| 992 |
if tally_geo is not None and layers.value['bounds'].value is not None:
|
| 993 |
((ymin,xmin),(ymax,xmax)) = layers.value['bounds'].value
|
| 994 |
tally_filtered = tally_geo.cx[xmin:xmax,ymin:ymax]
|
| 995 |
if tally_filter.value is not None:
|
| 996 |
tally_filtered = tally_filtered[tally_filter.value]
|
| 997 |
-
hazard_type = layers.value['hazard'].value
|
| 998 |
print('Triggering generate_metrics')
|
| 999 |
-
metrics = generate_metrics(tally_filtered, tally_geo,
|
| 1000 |
print('metrics', metrics)
|
| 1001 |
metric_update_pending.set(False)
|
| 1002 |
return metrics
|
|
@@ -1105,6 +1155,10 @@ def ExecutePanel():
|
|
| 1105 |
set_execute_counter(execute_counter + 1)
|
| 1106 |
execute_error.set("")
|
| 1107 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1108 |
def is_ready_to_run(infra, hazard):
|
| 1109 |
existing_layers = set([name for name, l in layers.value['layers'].items() if l['data'].value is not None])
|
| 1110 |
missing = []
|
|
@@ -1356,20 +1410,10 @@ def ExecutePanel():
|
|
| 1356 |
return buildings
|
| 1357 |
|
| 1358 |
def execute_metric():
|
| 1359 |
-
hazard_type = layers.value['hazard'].value
|
| 1360 |
landuse = layers.value['layers']['landuse']['data'].value
|
| 1361 |
buildings = layers.value['layers']['building']['data'].value
|
| 1362 |
household = layers.value['layers']['household']['data'].value
|
| 1363 |
individual = layers.value['layers']['individual']['data'].value
|
| 1364 |
-
policies = [p['id'] for _, p in layers.value['policies'].items() if f"{p['label']}/{p['description']}" in layers.value['selected_policies'].value]
|
| 1365 |
-
|
| 1366 |
-
# implementation_capacity_score = layers.value['implementation_capacity_score'].value
|
| 1367 |
-
# if implementation_capacity_score == 'medium':
|
| 1368 |
-
# capacity = 1.25
|
| 1369 |
-
# elif implementation_capacity_score == 'low':
|
| 1370 |
-
# capacity = 1.50
|
| 1371 |
-
# else:
|
| 1372 |
-
# capacity = 1
|
| 1373 |
|
| 1374 |
tally, tally_geo = create_tally(landuse, buildings, household, individual)
|
| 1375 |
return tally, tally_geo
|
|
@@ -1415,6 +1459,7 @@ def ExecutePanel():
|
|
| 1415 |
store_in_session_storage('tally', tally)
|
| 1416 |
store_in_session_storage('tally_geo', tally_geo)
|
| 1417 |
store_in_session_storage('tally_minimal', tally[layers.value['tally_filter_cols']])
|
|
|
|
| 1418 |
layers.value['tally_is_available'].value = True
|
| 1419 |
tally_counter.value += 1
|
| 1420 |
set_progress_message('')
|
|
@@ -1450,8 +1495,13 @@ def ExecutePanel():
|
|
| 1450 |
# )
|
| 1451 |
|
| 1452 |
solara.ProgressLinear(value=False)
|
| 1453 |
-
solara.
|
|
|
|
|
|
|
| 1454 |
disabled=execute_btn_disabled)
|
|
|
|
|
|
|
|
|
|
| 1455 |
if storage.value is not None:
|
| 1456 |
if layers.value['tally_is_available'].value and user.value is not None:
|
| 1457 |
solara.Button("Save Session",on_click=save_app_state, disabled=False)
|
|
@@ -1487,7 +1537,7 @@ def ExecutePanel():
|
|
| 1487 |
solara.Text("Spacer", style={"visibility": "hidden"})
|
| 1488 |
set_execute_btn_disabled(False)
|
| 1489 |
solara.ProgressLinear(value=False)
|
| 1490 |
-
|
| 1491 |
@solara.component
|
| 1492 |
def PolicyPanel():
|
| 1493 |
all_policies = [f"{p['label']}/{p['description']}" for _, p in layers.value['policies'].items()]
|
|
@@ -1737,6 +1787,7 @@ def ImportDataZone():
|
|
| 1737 |
@solara.component
|
| 1738 |
def WebApp():
|
| 1739 |
solara.Title(" ")
|
|
|
|
| 1740 |
with solara.Sidebar():
|
| 1741 |
with solara.lab.Tabs():
|
| 1742 |
with solara.lab.Tab("DATA IMPORT"):
|
|
|
|
| 39 |
tally_filter = solara.reactive(None)
|
| 40 |
building_filter = solara.reactive(None)
|
| 41 |
landuse_filter = solara.reactive(None)
|
| 42 |
+
center_default = (41.01,28.98)
|
| 43 |
def create_new_app_state():
|
| 44 |
return solara.reactive({
|
| 45 |
'infra': solara.reactive(["building"]),
|
|
|
|
| 235 |
'attributes': [set(['vuln_string', 'med_slight', 'med_moderate', 'med_extensive', 'med_complete',
|
| 236 |
'dispersion'])]}
|
| 237 |
},
|
| 238 |
+
'center': solara.reactive(center_default),
|
| 239 |
'selected_layer' : solara.reactive(None),
|
| 240 |
'render_count': solara.reactive(0),
|
| 241 |
'bounds': solara.reactive(None),
|
|
|
|
| 341 |
assign_nested_value(layers.value, keys, solara.reactive(src_value))
|
| 342 |
else:
|
| 343 |
assign_nested_value(layers.value, keys, src_value)
|
| 344 |
+
|
| 345 |
+
def store_info_to_session():
|
| 346 |
+
store_in_session_storage('population_displacement_consensus', population_displacement_consensus.value)
|
| 347 |
+
for layer_name in layers.value['layers'].keys():
|
| 348 |
+
store_in_session_storage(layer_name, {
|
| 349 |
+
'data':layers.value['layers'][layer_name]['data'].value,
|
| 350 |
+
'df': layers.value['layers'][layer_name]['df'].value,
|
| 351 |
+
})
|
| 352 |
+
for attr in ['hazard', 'tally_is_available', 'selected_policies','center',
|
| 353 |
+
'bounds','selected_layer','render_count','implementation_capacity_score',
|
| 354 |
+
'data_import_method','map_info_button','map_info_detail']:
|
| 355 |
+
store_in_session_storage(attr, layers.value[attr].value)
|
| 356 |
+
|
| 357 |
+
def reload_info_from_session():
|
| 358 |
+
session_data = read_from_session_storage('population_displacement_consensus')
|
| 359 |
+
if session_data is not None:
|
| 360 |
+
population_displacement_consensus.set(session_data)
|
| 361 |
+
for layer_name in layers.value['layers'].keys():
|
| 362 |
+
session_data = read_from_session_storage(layer_name)
|
| 363 |
+
if session_data is not None:
|
| 364 |
+
if layers.value['layers'][layer_name]['data'].value is None:
|
| 365 |
+
layers.value['layers'][layer_name]['data'].set(session_data['data'])
|
| 366 |
+
if layers.value['layers'][layer_name]['df'].value is None:
|
| 367 |
+
layers.value['layers'][layer_name]['df'].set(session_data['df'])
|
| 368 |
+
|
| 369 |
+
for attr in ['hazard', 'tally_is_available', 'selected_policies','center',
|
| 370 |
+
'bounds','selected_layer','render_count','implementation_capacity_score',
|
| 371 |
+
'data_import_method','map_info_button','map_info_detail']:
|
| 372 |
+
session_data = read_from_session_storage(attr)
|
| 373 |
+
if session_data is not None:
|
| 374 |
+
layers.value[attr].set(session_data)
|
| 375 |
+
|
| 376 |
+
def reset_session():
|
| 377 |
+
store_in_session_storage('population_displacement_consensus', None)
|
| 378 |
+
for layer_name in layers.value['layers'].keys():
|
| 379 |
+
store_in_session_storage(layer_name, None)
|
| 380 |
+
for attr in ['hazard', 'tally_is_available', 'selected_policies','center',
|
| 381 |
+
'bounds','selected_layer','render_count','implementation_capacity_score',
|
| 382 |
+
'data_import_method','map_info_button','map_info_detail']:
|
| 383 |
+
store_in_session_storage(attr, None)
|
| 384 |
+
store_in_session_storage('tally', None)
|
| 385 |
+
store_in_session_storage('tally_geo', None)
|
| 386 |
+
store_in_session_storage('tally_minimal', None)
|
| 387 |
+
layers.set(create_new_app_state().value)
|
| 388 |
+
tally_filter.set(None)
|
| 389 |
+
building_filter.set(None)
|
| 390 |
+
landuse_filter.set(None)
|
| 391 |
+
tally_counter.set(0)
|
| 392 |
+
|
| 393 |
def create_metadata(data):
|
| 394 |
m = dict()
|
| 395 |
m['hazard'] = data['hazard']
|
|
|
|
| 944 |
# filters[layer_name], _ = solara.use_cross_filter(id(df), "dataframe")
|
| 945 |
|
| 946 |
building = layers.value['layers']['building']['df'].value
|
| 947 |
+
building_filter.value, _ = solara.use_cross_filter(id(building), "building_filter")
|
| 948 |
if building is not None:
|
| 949 |
with solara.Row(): #spacer
|
| 950 |
solara.Markdown('''<h5 style=""></h5>''')
|
| 951 |
btn = solara.Button("BUILDING FILTERS")
|
| 952 |
with solara.Column(align="stretch"):
|
| 953 |
with solara.lab.Menu(activator=btn, close_on_content_click=False, style={"width":"35vh", "align":"stretch"}): #"height":"60vh"
|
|
|
|
| 954 |
solara.CrossFilterReport(building)
|
| 955 |
solara.CrossFilterSelect(building, "ds", multiple=True)
|
| 956 |
solara.CrossFilterSelect(building, "specialfac", multiple=True)
|
|
|
|
| 961 |
solara.CrossFilterSelect(building, "code_level", multiple=True)
|
| 962 |
solara.CrossFilterSelect(building, "material", multiple=True)
|
| 963 |
solara.CrossFilterSelect(building, "zoneid", multiple=True)
|
| 964 |
+
|
| 965 |
landuse = layers.value['layers']['landuse']['df'].value
|
| 966 |
+
landuse_filter.value, _ = solara.use_cross_filter(id(landuse), "landuse_filter")
|
| 967 |
if landuse is not None:
|
| 968 |
with solara.Row(): #spacer
|
| 969 |
solara.Markdown('''<h5 style=""></h5>''')
|
| 970 |
btn = solara.Button("LANDUSE FILTERS")
|
| 971 |
with solara.Column(align="stretch"):
|
| 972 |
with solara.lab.Menu(activator=btn, close_on_content_click=False, style={"width":"35vh", "align":"stretch"}): #"height":"60vh"
|
|
|
|
| 973 |
solara.CrossFilterReport(landuse)
|
| 974 |
solara.CrossFilterSelect(landuse, "luf", multiple=True)
|
| 975 |
solara.CrossFilterSelect(landuse, "avgincome", multiple=True)
|
| 976 |
|
| 977 |
+
|
| 978 |
tc = tally_counter.value
|
| 979 |
print('tally_counter', tc)
|
| 980 |
tally_minimal = read_from_session_storage('tally_minimal')
|
| 981 |
+
tally_filter.value, _ = solara.use_cross_filter(id(tally_minimal), "tally_filter")
|
| 982 |
if tally_minimal is not None:
|
| 983 |
with solara.Row(): #spacer
|
| 984 |
solara.Markdown('''<h5 style=""></h5>''')
|
| 985 |
btn = solara.Button("METRIC FILTERS")
|
| 986 |
with solara.Column(align="stretch"):
|
| 987 |
with solara.lab.Menu(activator=btn, close_on_content_click=False, style={"width":"35vh", "align":"stretch"}): #"height":"60vh"
|
|
|
|
| 988 |
solara.CrossFilterReport(tally_minimal)
|
| 989 |
for col in layers.value['tally_filter_cols']:
|
| 990 |
solara.CrossFilterSelect(tally_minimal, col, multiple=True)
|
|
|
|
| 1038 |
metrics = {name: {'value':0, 'max_value':0, 'desc': metric['desc']} for name, metric in layers.value['metrics'].items()}
|
| 1039 |
|
| 1040 |
tally_geo = read_from_session_storage('tally_geo')
|
| 1041 |
+
hazard = read_from_session_storage('hazard')
|
| 1042 |
+
population_displacement_consensus = read_from_session_storage('population_displacement_consensus')
|
| 1043 |
if tally_geo is not None and layers.value['bounds'].value is not None:
|
| 1044 |
((ymin,xmin),(ymax,xmax)) = layers.value['bounds'].value
|
| 1045 |
tally_filtered = tally_geo.cx[xmin:xmax,ymin:ymax]
|
| 1046 |
if tally_filter.value is not None:
|
| 1047 |
tally_filtered = tally_filtered[tally_filter.value]
|
|
|
|
| 1048 |
print('Triggering generate_metrics')
|
| 1049 |
+
metrics = generate_metrics(tally_filtered, tally_geo, hazard, population_displacement_consensus)
|
| 1050 |
print('metrics', metrics)
|
| 1051 |
metric_update_pending.set(False)
|
| 1052 |
return metrics
|
|
|
|
| 1155 |
set_execute_counter(execute_counter + 1)
|
| 1156 |
execute_error.set("")
|
| 1157 |
|
| 1158 |
+
def on_reset():
|
| 1159 |
+
reset_session()
|
| 1160 |
+
|
| 1161 |
+
|
| 1162 |
def is_ready_to_run(infra, hazard):
|
| 1163 |
existing_layers = set([name for name, l in layers.value['layers'].items() if l['data'].value is not None])
|
| 1164 |
missing = []
|
|
|
|
| 1410 |
return buildings
|
| 1411 |
|
| 1412 |
def execute_metric():
|
|
|
|
| 1413 |
landuse = layers.value['layers']['landuse']['data'].value
|
| 1414 |
buildings = layers.value['layers']['building']['data'].value
|
| 1415 |
household = layers.value['layers']['household']['data'].value
|
| 1416 |
individual = layers.value['layers']['individual']['data'].value
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1417 |
|
| 1418 |
tally, tally_geo = create_tally(landuse, buildings, household, individual)
|
| 1419 |
return tally, tally_geo
|
|
|
|
| 1459 |
store_in_session_storage('tally', tally)
|
| 1460 |
store_in_session_storage('tally_geo', tally_geo)
|
| 1461 |
store_in_session_storage('tally_minimal', tally[layers.value['tally_filter_cols']])
|
| 1462 |
+
store_info_to_session()
|
| 1463 |
layers.value['tally_is_available'].value = True
|
| 1464 |
tally_counter.value += 1
|
| 1465 |
set_progress_message('')
|
|
|
|
| 1495 |
# )
|
| 1496 |
|
| 1497 |
solara.ProgressLinear(value=False)
|
| 1498 |
+
with solara.Columns([70,30]):
|
| 1499 |
+
with solara.Column():
|
| 1500 |
+
solara.Button("Calculate", on_click=on_click, outlined=True,
|
| 1501 |
disabled=execute_btn_disabled)
|
| 1502 |
+
with solara.Column():
|
| 1503 |
+
solara.Button("Reset", on_click=on_reset, outlined=True,
|
| 1504 |
+
disabled=False)
|
| 1505 |
if storage.value is not None:
|
| 1506 |
if layers.value['tally_is_available'].value and user.value is not None:
|
| 1507 |
solara.Button("Save Session",on_click=save_app_state, disabled=False)
|
|
|
|
| 1537 |
solara.Text("Spacer", style={"visibility": "hidden"})
|
| 1538 |
set_execute_btn_disabled(False)
|
| 1539 |
solara.ProgressLinear(value=False)
|
| 1540 |
+
|
| 1541 |
@solara.component
|
| 1542 |
def PolicyPanel():
|
| 1543 |
all_policies = [f"{p['label']}/{p['description']}" for _, p in layers.value['policies'].items()]
|
|
|
|
| 1787 |
@solara.component
|
| 1788 |
def WebApp():
|
| 1789 |
solara.Title(" ")
|
| 1790 |
+
reload_info_from_session()
|
| 1791 |
with solara.Sidebar():
|
| 1792 |
with solara.lab.Tabs():
|
| 1793 |
with solara.lab.Tab("DATA IMPORT"):
|