hkayabilisim commited on
Commit
07fcfdd
·
1 Parent(s): 3cd1622

Added mapinfo panel

Browse files
tomorrowcities/content/articles/welcome.md CHANGED
@@ -15,7 +15,9 @@ 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
- 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.
 
 
19
 
20
  ### New policies
21
  * Eight new policies are added. See their definitions [here](/docs/policies)
 
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.
21
 
22
  ### New policies
23
  * Eight new policies are added. See their definitions [here](/docs/policies)
tomorrowcities/pages/engine.py CHANGED
@@ -15,9 +15,12 @@ import logging, sys
15
 
16
  from ..backend.engine import compute, compute_power_infra, calculate_metrics
17
 
 
18
  layers = solara.reactive({
19
  'layers' : {
20
  'building': {
 
 
21
  'df': solara.reactive(None),
22
  'map_layer': solara.reactive(None),
23
  'force_render': solara.reactive(False),
@@ -26,6 +29,8 @@ layers = solara.reactive({
26
  'cols_required': set(['residents', 'fptarea', 'repvalue', 'nhouse', 'zoneid', 'expstr', 'bldid', 'geometry', 'specialfac']),
27
  'cols': set(['residents', 'fptarea', 'repvalue', 'nhouse', 'zoneid', 'expstr', 'bldid', 'geometry', 'specialfac'])},
28
  'landuse': {
 
 
29
  'df': solara.reactive(None),
30
  'map_layer': solara.reactive(None),
31
  'force_render': solara.reactive(False),
@@ -34,7 +39,9 @@ layers = solara.reactive({
34
  'cols_required': set(['geometry', 'zoneid', 'luf', 'population', 'densitycap', 'avgincome']),
35
  'cols': set(['geometry', 'zoneid', 'luf', 'population', 'densitycap', 'floorarat', 'setback', 'avgincome'])},
36
  'household': {
 
37
  'df': solara.reactive(None),
 
38
  'map_layer': solara.reactive(None),
39
  'force_render': solara.reactive(False),
40
  'visible': solara.reactive(False),
@@ -42,7 +49,9 @@ layers = solara.reactive({
42
  'cols_required':set(['hhid', 'nind', 'income', 'bldid', 'commfacid']),
43
  'cols':set(['hhid', 'nind', 'income', 'bldid', 'commfacid'])},
44
  'individual': {
 
45
  'df': solara.reactive(None),
 
46
  'map_layer': solara.reactive(None),
47
  'force_render': solara.reactive(False),
48
  'visible': solara.reactive(False),
@@ -50,7 +59,9 @@ layers = solara.reactive({
50
  'cols_required': set(['individ', 'hhid', 'gender', 'age', 'eduattstat', 'head', 'indivfacid']),
51
  'cols': set(['individ', 'hhid', 'gender', 'age', 'eduattstat', 'head', 'indivfacid'])},
52
  'intensity': {
 
53
  'df': solara.reactive(None),
 
54
  'map_layer': solara.reactive(None),
55
  'force_render': solara.reactive(False),
56
  'visible': solara.reactive(False),
@@ -58,7 +69,9 @@ layers = solara.reactive({
58
  'cols_required': set(['geometry','im']),
59
  'cols': set(['geometry','im'])},
60
  'fragility': {
 
61
  'df': solara.reactive(None),
 
62
  'map_layer': solara.reactive(None),
63
  'force_render': solara.reactive(False),
64
  'visible': solara.reactive(False),
@@ -66,7 +79,9 @@ layers = solara.reactive({
66
  'cols_required': set(['expstr','muds1_g','muds2_g','muds3_g','muds4_g','sigmads1','sigmads2','sigmads3','sigmads4']),
67
  'cols': set(['expstr','muds1_g','muds2_g','muds3_g','muds4_g','sigmads1','sigmads2','sigmads3','sigmads4'])},
68
  'vulnerability': {
 
69
  'df': solara.reactive(None),
 
70
  'map_layer': solara.reactive(None),
71
  'force_render': solara.reactive(False),
72
  'visible': solara.reactive(False),
@@ -74,7 +89,9 @@ layers = solara.reactive({
74
  'cols_required': set(['expstr', 'hw0', 'hw0_5', 'hw1', 'hw1_5', 'hw2', 'hw3', 'hw4', 'hw5','hw6']),
75
  'cols': set(['expstr', 'hw0', 'hw0_5', 'hw1', 'hw1_5', 'hw2', 'hw3', 'hw4', 'hw5','hw6'])},
76
  'power nodes': {
 
77
  'df': solara.reactive(None),
 
78
  'map_layer': solara.reactive(None),
79
  'force_render': solara.reactive(False),
80
  'visible': solara.reactive(False),
@@ -86,7 +103,9 @@ layers = solara.reactive({
86
  'node_id', 'x_coord', 'y_coord', 'pwr_plant', 'serv_area', 'n_bldgs',
87
  'income', 'eq_vuln'])},
88
  'power edges': {
 
89
  'df': solara.reactive(None),
 
90
  'map_layer': solara.reactive(None),
91
  'force_render': solara.reactive(False),
92
  'visible': solara.reactive(False),
@@ -96,7 +115,9 @@ layers = solara.reactive({
96
  'cols': set(['from_node', 'direction', 'pipetype', 'edge_id', 'guid', 'capacity',
97
  'geometry', 'to_node', 'length'])},
98
  'power fragility': {
 
99
  'df': solara.reactive(None),
 
100
  'map_layer': solara.reactive(None),
101
  'force_render': solara.reactive(False),
102
  'visible': solara.reactive(False),
@@ -123,6 +144,8 @@ layers = solara.reactive({
123
  '10': {'id':10, 'label': 'P10', 'description': 'Enforcement of environmental protection zones', 'applied': solara.reactive(False)},
124
  },
125
  'implementation_capacity_score': solara.reactive("high"),
 
 
126
  'metrics': {
127
  "metric1": {"desc": "Number of workers unemployed", "value": 0, "max_value": 100},
128
  "metric2": {"desc": "Number of children with no access to education", "value": 0, "max_value": 100},
@@ -138,6 +161,86 @@ def building_colors(feature):
138
  ds = feature['properties']['ds']
139
  return {'fillColor': 'black', 'color': 'red' if ds > 0 else 'blue' }
140
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  def power_node_colors(feature):
142
  print(feature)
143
  ds_to_color = {0: 'lavender', 1:'violet',2:'fuchsia',3:'indigo',4:'darkslateblue',5:'black'}
@@ -160,12 +263,19 @@ def create_map_layer(df, name):
160
  if name == "intensity":
161
  locs = np.array([df.geometry.y.to_list(), df.geometry.x.to_list(), df.im.to_list()]).transpose().tolist()
162
  map_layer = ipyleaflet.Heatmap(locations=locs, radius = 10)
 
 
 
 
 
 
163
  elif name == "building":
164
  map_layer = ipyleaflet.GeoJSON(data = json.loads(df.to_json()),
165
- style={'opacity': 1, 'fillOpacity': 0.5, 'weight': 1},
166
- hover_style={'color': 'blue', 'dashArray': '0', 'fillOpacity': 0.5},
167
- style_callback=building_colors)
168
-
 
169
  elif name == "power nodes":
170
  markers = []
171
  for index, node in df.iterrows():
@@ -201,7 +311,7 @@ def MetricWidget(name, description, value, max_value, render_count):
201
  "type": 'gauge',
202
  "min": 0,
203
  "name": description,
204
- "max": max_value,
205
  "startAngle": 180,
206
  "endAngle": 0,
207
  "progress": {"show": True, "width": 8},
@@ -334,7 +444,8 @@ def LayerDisplayer():
334
  df = nonempty_layers[selected]['df'].value
335
  if "geometry" in df.columns:
336
  ((ymin,xmin),(ymax,xmax)) = layers.value['bounds'].value
337
- solara.DataFrame(df.cx[xmin:xmax,ymin:ymax].drop(columns='geometry'))
 
338
  else:
339
  solara.DataFrame(df)
340
  if selected == "building":
@@ -384,7 +495,8 @@ def MapViewer():
384
  base_layer = ipyleaflet.TileLayer.element(url=base_map.build_url())
385
  map_layers = [base_layer]
386
 
387
- for layer_name, layer in layers.value['layers'].items():
 
388
  df = layer['df'].value
389
  if df is None:
390
  continue
@@ -575,17 +687,57 @@ def PolicyPanel():
575
  solara.Button(icon_name="mdi-help-circle-outline", icon=True)
576
 
577
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
578
  @solara.component
579
  def WebApp():
580
 
581
- with solara.Columns([30,60]):
582
  with solara.Column():
583
  solara.Markdown('[Download Sample Dataset](https://drive.google.com/file/d/1BGPZQ2IKJHY9ExOCCHcNNrCTioYZ8D1y/view?usp=sharing)')
584
  FileDropZone()
585
  ExecutePanel()
586
  with solara.Column():
587
  LayerController()
588
- MapViewer()
 
 
589
  MetricPanel()
590
 
591
  LayerDisplayer()
 
15
 
16
  from ..backend.engine import compute, compute_power_infra, calculate_metrics
17
 
18
+
19
  layers = solara.reactive({
20
  'layers' : {
21
  'building': {
22
+ 'render_order': 50,
23
+ 'map_info_tooltip': 'Number of buildings',
24
  'df': solara.reactive(None),
25
  'map_layer': solara.reactive(None),
26
  'force_render': solara.reactive(False),
 
29
  'cols_required': set(['residents', 'fptarea', 'repvalue', 'nhouse', 'zoneid', 'expstr', 'bldid', 'geometry', 'specialfac']),
30
  'cols': set(['residents', 'fptarea', 'repvalue', 'nhouse', 'zoneid', 'expstr', 'bldid', 'geometry', 'specialfac'])},
31
  'landuse': {
32
+ 'render_order': 20,
33
+ 'map_info_tooltip': 'Number of landuse zones',
34
  'df': solara.reactive(None),
35
  'map_layer': solara.reactive(None),
36
  'force_render': solara.reactive(False),
 
39
  'cols_required': set(['geometry', 'zoneid', 'luf', 'population', 'densitycap', 'avgincome']),
40
  'cols': set(['geometry', 'zoneid', 'luf', 'population', 'densitycap', 'floorarat', 'setback', 'avgincome'])},
41
  'household': {
42
+ 'render_order': 0,
43
  'df': solara.reactive(None),
44
+ 'map_info_tooltip': 'Number of households',
45
  'map_layer': solara.reactive(None),
46
  'force_render': solara.reactive(False),
47
  'visible': solara.reactive(False),
 
49
  'cols_required':set(['hhid', 'nind', 'income', 'bldid', 'commfacid']),
50
  'cols':set(['hhid', 'nind', 'income', 'bldid', 'commfacid'])},
51
  'individual': {
52
+ 'render_order': 0,
53
  'df': solara.reactive(None),
54
+ 'map_info_tooltip': 'Number of individuals',
55
  'map_layer': solara.reactive(None),
56
  'force_render': solara.reactive(False),
57
  'visible': solara.reactive(False),
 
59
  'cols_required': set(['individ', 'hhid', 'gender', 'age', 'eduattstat', 'head', 'indivfacid']),
60
  'cols': set(['individ', 'hhid', 'gender', 'age', 'eduattstat', 'head', 'indivfacid'])},
61
  'intensity': {
62
+ 'render_order': 0,
63
  'df': solara.reactive(None),
64
+ 'map_info_tooltip': 'Number of intensity measurements',
65
  'map_layer': solara.reactive(None),
66
  'force_render': solara.reactive(False),
67
  'visible': solara.reactive(False),
 
69
  'cols_required': set(['geometry','im']),
70
  'cols': set(['geometry','im'])},
71
  'fragility': {
72
+ 'render_order': 0,
73
  'df': solara.reactive(None),
74
+ 'map_info_tooltip': 'Number of records in fragility configuration',
75
  'map_layer': solara.reactive(None),
76
  'force_render': solara.reactive(False),
77
  'visible': solara.reactive(False),
 
79
  'cols_required': set(['expstr','muds1_g','muds2_g','muds3_g','muds4_g','sigmads1','sigmads2','sigmads3','sigmads4']),
80
  'cols': set(['expstr','muds1_g','muds2_g','muds3_g','muds4_g','sigmads1','sigmads2','sigmads3','sigmads4'])},
81
  'vulnerability': {
82
+ 'render_order': 0,
83
  'df': solara.reactive(None),
84
+ 'map_info_tooltip': 'Number of records in vulnerabilty configuration',
85
  'map_layer': solara.reactive(None),
86
  'force_render': solara.reactive(False),
87
  'visible': solara.reactive(False),
 
89
  'cols_required': set(['expstr', 'hw0', 'hw0_5', 'hw1', 'hw1_5', 'hw2', 'hw3', 'hw4', 'hw5','hw6']),
90
  'cols': set(['expstr', 'hw0', 'hw0_5', 'hw1', 'hw1_5', 'hw2', 'hw3', 'hw4', 'hw5','hw6'])},
91
  'power nodes': {
92
+ 'render_order': 90,
93
  'df': solara.reactive(None),
94
+ 'map_info_tooltip': 'Number of electrical power nodes',
95
  'map_layer': solara.reactive(None),
96
  'force_render': solara.reactive(False),
97
  'visible': solara.reactive(False),
 
103
  'node_id', 'x_coord', 'y_coord', 'pwr_plant', 'serv_area', 'n_bldgs',
104
  'income', 'eq_vuln'])},
105
  'power edges': {
106
+ 'render_order': 80,
107
  'df': solara.reactive(None),
108
+ 'map_info_tooltip': 'Number of connections in power grid',
109
  'map_layer': solara.reactive(None),
110
  'force_render': solara.reactive(False),
111
  'visible': solara.reactive(False),
 
115
  'cols': set(['from_node', 'direction', 'pipetype', 'edge_id', 'guid', 'capacity',
116
  'geometry', 'to_node', 'length'])},
117
  'power fragility': {
118
+ 'render_order': 0,
119
  'df': solara.reactive(None),
120
+ 'map_info_tooltip': 'Number of records in fragility configuration for power',
121
  'map_layer': solara.reactive(None),
122
  'force_render': solara.reactive(False),
123
  'visible': solara.reactive(False),
 
144
  '10': {'id':10, 'label': 'P10', 'description': 'Enforcement of environmental protection zones', 'applied': solara.reactive(False)},
145
  },
146
  'implementation_capacity_score': solara.reactive("high"),
147
+ 'map_info_button': solara.reactive("summary"),
148
+ 'map_info_detail': solara.reactive({}),
149
  'metrics': {
150
  "metric1": {"desc": "Number of workers unemployed", "value": 0, "max_value": 100},
151
  "metric2": {"desc": "Number of children with no access to education", "value": 0, "max_value": 100},
 
161
  ds = feature['properties']['ds']
162
  return {'fillColor': 'black', 'color': 'red' if ds > 0 else 'blue' }
163
 
164
+ def building_click_handler(event=None, feature=None, id=None, properties=None):
165
+ layers.value['map_info_detail'].set(properties)
166
+ layers.value['map_info_button'].set("detail")
167
+ layers.value['map_info_force_render'].set(True)
168
+
169
+ def landuse_click_handler(event=None, feature=None, id=None, properties=None):
170
+ layers.value['map_info_detail'].set(properties)
171
+ layers.value['map_info_button'].set("detail")
172
+ layers.value['map_info_force_render'].set(True)
173
+
174
+ def landuse_colors(feature):
175
+ print(feature)
176
+ luf_type = feature['properties']['luf']
177
+ if luf_type == 'RESIDENTIAL (HIGH DENSITY)':
178
+ luf_color = {
179
+ 'color': 'black',
180
+ 'fillColor': '#A0522D', # sienna
181
+ }
182
+ elif luf_type == 'HISTORICAL PRESERVATION AREA':
183
+ luf_color = {
184
+ 'color': 'black',
185
+ 'fillColor': '#673147', # plum
186
+ }
187
+ elif luf_type == 'RESIDENTIAL (MODERATE DENSITY)':
188
+ luf_color = {
189
+ 'color': 'black',
190
+ 'fillColor': '#cd853f', # peru
191
+ }
192
+ elif luf_type == 'COMMERCIAL AND RESIDENTIAL':
193
+ luf_color = {
194
+ 'color': 'black',
195
+ 'fillColor': 'red',
196
+ }
197
+ elif luf_type == 'CITY CENTER':
198
+ luf_color = {
199
+ 'color': 'black',
200
+ 'fillColor': '#E6E6FA', # lavender
201
+ }
202
+ elif luf_type == 'INDUSTRY':
203
+ luf_color = {
204
+ 'color': 'black',
205
+ 'fillColor': 'grey',
206
+ }
207
+ elif luf_type == 'RESIDENTIAL (LOW DENSITY)':
208
+ luf_color= {
209
+ 'color': 'black',
210
+ 'fillColor': '#D2B48C', # tan
211
+ }
212
+ elif luf_type == 'RESIDENTIAL (GATED NEIGHBORHOOD)':
213
+ luf_color= {
214
+ 'color': 'black',
215
+ 'fillColor': 'orange',
216
+ }
217
+ elif luf_type == 'AGRICULTURE':
218
+ luf_color= {
219
+ 'color': 'black',
220
+ 'fillColor': 'yellow',
221
+ }
222
+ elif luf_type == 'FOREST':
223
+ luf_color= {
224
+ 'color': 'black',
225
+ 'fillColor': 'green',
226
+ }
227
+ elif luf_type == 'VACANT ZONE':
228
+ luf_color = {
229
+ 'color': 'black',
230
+ 'fillColor': '#90EE90', # lightgreen
231
+ }
232
+ elif luf_type == 'RECREATION AREA':
233
+ luf_color = {
234
+ 'color': 'black',
235
+ 'fillColor': '#32CD32', #lime
236
+ }
237
+ else:
238
+ luf_color = {
239
+ 'color': 'black',
240
+ 'fillColor': random.choice(['red', 'yellow', 'green', 'orange','blue']),
241
+ }
242
+ return luf_color
243
+
244
  def power_node_colors(feature):
245
  print(feature)
246
  ds_to_color = {0: 'lavender', 1:'violet',2:'fuchsia',3:'indigo',4:'darkslateblue',5:'black'}
 
263
  if name == "intensity":
264
  locs = np.array([df.geometry.y.to_list(), df.geometry.x.to_list(), df.im.to_list()]).transpose().tolist()
265
  map_layer = ipyleaflet.Heatmap(locations=locs, radius = 10)
266
+ elif name == "landuse":
267
+ map_layer = ipyleaflet.GeoJSON(data = json.loads(df.to_json()),
268
+ style={'opacity': 1, 'dashArray': '9', 'fillOpacity': 0.5, 'weight': 1},
269
+ hover_style={'color': 'white', 'dashArray': '0', 'fillOpacity': 0.5},
270
+ style_callback=landuse_colors)
271
+ map_layer.on_click(building_click_handler)
272
  elif name == "building":
273
  map_layer = ipyleaflet.GeoJSON(data = json.loads(df.to_json()),
274
+ style={'opacity': 1, 'dashArray': '9', 'fillOpacity': 0.5, 'weight': 1},
275
+ hover_style={'color': 'white', 'dashArray': '0', 'fillOpacity': 0.5},
276
+ style_callback=building_colors)
277
+ map_layer.on_click(landuse_click_handler)
278
+
279
  elif name == "power nodes":
280
  markers = []
281
  for index, node in df.iterrows():
 
311
  "type": 'gauge',
312
  "min": 0,
313
  "name": description,
314
+ "max": max(1,max_value), # workaround when max_value = 0
315
  "startAngle": 180,
316
  "endAngle": 0,
317
  "progress": {"show": True, "width": 8},
 
444
  df = nonempty_layers[selected]['df'].value
445
  if "geometry" in df.columns:
446
  ((ymin,xmin),(ymax,xmax)) = layers.value['bounds'].value
447
+ df_filtered = df.cx[xmin:xmax,ymin:ymax].drop(columns='geometry')
448
+ solara.DataFrame(df_filtered)
449
  else:
450
  solara.DataFrame(df)
451
  if selected == "building":
 
495
  base_layer = ipyleaflet.TileLayer.element(url=base_map.build_url())
496
  map_layers = [base_layer]
497
 
498
+ render_order = [l['render_order'] for _, l in layers.value['layers'].items()]
499
+ for _, (layer_name, layer) in sorted(zip(render_order,layers.value['layers'].items())):
500
  df = layer['df'].value
501
  if df is None:
502
  continue
 
687
  solara.Button(icon_name="mdi-help-circle-outline", icon=True)
688
 
689
 
690
+ @solara.component
691
+ def MapInfo():
692
+ print(f'{layers.value["bounds"].value}')
693
+
694
+ print(layers.value['map_info_button'].value)
695
+
696
+ with solara.Row(justify="center"):
697
+ solara.ToggleButtonsSingle(value=layers.value['map_info_button'].value,
698
+ on_value=layers.value['map_info_button'].set,
699
+ values=["summary","detail"])
700
+
701
+ if layers.value['map_info_button'].value == "summary":
702
+ with solara.GridFixed(columns=2,row_gap="1px"):
703
+ for layer_name,layer in layers.value['layers'].items():
704
+ with solara.Tooltip(layer['map_info_tooltip']):
705
+ solara.Text(f'{layer_name}')
706
+ with solara.Row(justify="right"):
707
+ if layer['df'].value is None:
708
+ solara.Text('0')
709
+ else:
710
+ solara.Text(f"{len(layer['df'].value)}")
711
+ else:
712
+ with solara.GridFixed(columns=2,row_gap="1px"):
713
+ for key, value in layers.value['map_info_detail'].value.items():
714
+ if key == 'style':
715
+ continue
716
+ solara.Text(f'{key}')
717
+ with solara.Row(justify="right"):
718
+ strvalue = str(value)
719
+ if len(strvalue) > 10:
720
+ with solara.Tooltip(f'{value}'):
721
+ solara.Text(f'{strvalue[:10]}...')
722
+ else:
723
+ solara.Text(f'{value}')
724
+
725
+
726
+
727
+
728
  @solara.component
729
  def WebApp():
730
 
731
+ with solara.Columns([30,70]):
732
  with solara.Column():
733
  solara.Markdown('[Download Sample Dataset](https://drive.google.com/file/d/1BGPZQ2IKJHY9ExOCCHcNNrCTioYZ8D1y/view?usp=sharing)')
734
  FileDropZone()
735
  ExecutePanel()
736
  with solara.Column():
737
  LayerController()
738
+ with solara.Columns([80,20]):
739
+ MapViewer()
740
+ MapInfo()
741
  MetricPanel()
742
 
743
  LayerDisplayer()