pgzmnk commited on
Commit
4c8c6b4
1 Parent(s): 84e5c53
Files changed (2) hide show
  1. app.py +74 -49
  2. utils/js.py +1 -1
app.py CHANGED
@@ -240,8 +240,11 @@ def create_dataframe(years, project_name):
240
  dfs.append(df)
241
  return pd.concat(dfs)
242
 
 
243
  # h/t: https://community.plotly.com/t/dynamic-zoom-for-mapbox/32658/12
244
- def get_plotting_zoom_level_and_center_coordinates_from_lonlat_tuples(longitudes=None, latitudes=None):
 
 
245
  """Function documentation:\n
246
  Basic framework adopted from Krichardson under the following thread:
247
  https://community.plotly.com/t/dynamic-zoom-for-mapbox/32658/7
@@ -256,19 +259,18 @@ def get_plotting_zoom_level_and_center_coordinates_from_lonlat_tuples(longitudes
256
 
257
  # Check whether both latitudes and longitudes have been passed,
258
  # or if the list lenghts don't match
259
- if ((latitudes is None or longitudes is None)
260
- or (len(latitudes) != len(longitudes))):
261
  # Otherwise, return the default values of 0 zoom and the coordinate origin as center point
262
  return 0, (0, 0)
263
 
264
- # Get the boundary-box
265
- b_box = {}
266
- b_box['height'] = latitudes.max()-latitudes.min()
267
- b_box['width'] = longitudes.max()-longitudes.min()
268
- b_box['center']= (np.mean(longitudes), np.mean(latitudes))
269
 
270
  # get the area of the bounding box in order to calculate a zoom-level
271
- area = b_box['height'] * b_box['width']
272
 
273
  # * 1D-linear interpolation with numpy:
274
  # - Pass the area as the only x-value and not as a list, in order to return a scalar as well
@@ -276,52 +278,70 @@ def get_plotting_zoom_level_and_center_coordinates_from_lonlat_tuples(longitudes
276
  # - The zpom-levels are adapted to the areas, i.e. start with the smallest area possible of 0
277
  # which leads to the highest possible zoom value 20, and so forth decreasing with increasing areas
278
  # as these variables are antiproportional
279
- zoom = np.interp(x=area,
280
- xp=[0, 5**-10, 4**-10, 3**-10, 2**-10, 1**-10, 1**-5],
281
- fp=[20, 15, 14, 13, 12, 7, 5])
 
 
282
 
283
  # Finally, return the zoom level and the associated boundary-box center coordinates
284
- return zoom, b_box['center']
 
285
 
286
  def show_project_map(project_name):
287
- prepared_statement = \
288
- con.execute("SELECT geometry FROM project WHERE name = ? LIMIT 1",
289
- [project_name]).fetchall()
290
- features = \
291
- json.loads(prepared_statement[0][0].replace("\'", "\""))['features']
292
- geometry = features[0]['geometry']
293
  longitudes = np.array(geometry["coordinates"])[0, :, 0]
294
  latitudes = np.array(geometry["coordinates"])[0, :, 1]
295
- zoom, bbox_center = get_plotting_zoom_level_and_center_coordinates_from_lonlat_tuples(longitudes, latitudes)
296
- fig = go.Figure(go.Scattermapbox(
297
- mode = "markers",
298
- lon = [bbox_center[0]], lat = [bbox_center[1]],
299
- marker = {'size': 20, 'color': ["cyan"]}))
 
 
 
 
 
 
 
 
 
300
 
301
  fig.update_layout(
302
- mapbox = {
303
- 'style': "stamen-terrain",
304
- 'center': { 'lon': bbox_center[0], 'lat': bbox_center[1]},
305
- 'zoom': zoom, 'layers': [{
306
- 'source': {
307
- 'type': "FeatureCollection",
308
- 'features': [{
309
- 'type': "Feature",
310
- 'geometry': geometry
311
- }]
312
- },
313
- 'type': "fill", 'below': "traces", 'color': "royalblue"}]},
314
- margin = {'l':0, 'r':0, 'b':0, 't':0})
315
-
 
 
 
 
 
316
  return fig
317
 
 
318
  # minMax.getInfo()
319
  def calculate_biodiversity_score(start_year, end_year, project_name):
320
  years = []
321
  for year in range(start_year, end_year):
322
- row_exists = \
323
- con.execute("SELECT COUNT(1) FROM bioindicator WHERE (year = ? AND project_name = ?)",
324
- [year, project_name]).fetchall()[0][0]
 
325
  if not row_exists:
326
  years.append(year)
327
 
@@ -338,7 +358,8 @@ def calculate_biodiversity_score(start_year, end_year, project_name):
338
  """
339
  USE climatebase;
340
  CREATE TABLE IF NOT EXISTS bioindicator (year BIGINT, project_name VARCHAR(255), value DOUBLE, area DOUBLE, score DOUBLE, CONSTRAINT unique_year_project_name UNIQUE (year, project_name));
341
- """)
 
342
  # UPSERT project record
343
  con.sql(
344
  """
@@ -347,14 +368,18 @@ def calculate_biodiversity_score(start_year, end_year, project_name):
347
  """
348
  )
349
  logging.info("upsert records into motherduck")
350
- scores = \
351
- con.execute("SELECT * FROM bioindicator WHERE (year >= ? AND year <= ? AND project_name = ?)",
352
- [start_year, end_year, project_name]).df()
 
353
  return scores
354
 
 
355
  def motherduck_list_projects(author_id):
356
- return \
357
- con.execute("SELECT DISTINCT name FROM project WHERE authorId = ? AND geometry != 'null'", [author_id]).df()
 
 
358
 
359
 
360
  with gr.Blocks() as demo:
@@ -385,7 +410,7 @@ with gr.Blocks() as demo:
385
  fn=show_project_map,
386
  inputs=[project_name],
387
  outputs=[m1],
388
- )
389
 
390
  def update_project_dropdown_list(url_params):
391
  username = url_params.get("username", "default")
@@ -410,4 +435,4 @@ with gr.Blocks() as demo:
410
  queue=False,
411
  )
412
 
413
- demo.launch()
 
240
  dfs.append(df)
241
  return pd.concat(dfs)
242
 
243
+
244
  # h/t: https://community.plotly.com/t/dynamic-zoom-for-mapbox/32658/12
245
+ def get_plotting_zoom_level_and_center_coordinates_from_lonlat_tuples(
246
+ longitudes=None, latitudes=None
247
+ ):
248
  """Function documentation:\n
249
  Basic framework adopted from Krichardson under the following thread:
250
  https://community.plotly.com/t/dynamic-zoom-for-mapbox/32658/7
 
259
 
260
  # Check whether both latitudes and longitudes have been passed,
261
  # or if the list lenghts don't match
262
+ if (latitudes is None or longitudes is None) or (len(latitudes) != len(longitudes)):
 
263
  # Otherwise, return the default values of 0 zoom and the coordinate origin as center point
264
  return 0, (0, 0)
265
 
266
+ # Get the boundary-box
267
+ b_box = {}
268
+ b_box["height"] = latitudes.max() - latitudes.min()
269
+ b_box["width"] = longitudes.max() - longitudes.min()
270
+ b_box["center"] = (np.mean(longitudes), np.mean(latitudes))
271
 
272
  # get the area of the bounding box in order to calculate a zoom-level
273
+ area = b_box["height"] * b_box["width"]
274
 
275
  # * 1D-linear interpolation with numpy:
276
  # - Pass the area as the only x-value and not as a list, in order to return a scalar as well
 
278
  # - The zpom-levels are adapted to the areas, i.e. start with the smallest area possible of 0
279
  # which leads to the highest possible zoom value 20, and so forth decreasing with increasing areas
280
  # as these variables are antiproportional
281
+ zoom = np.interp(
282
+ x=area,
283
+ xp=[0, 5**-10, 4**-10, 3**-10, 2**-10, 1**-10, 1**-5],
284
+ fp=[20, 15, 14, 13, 12, 7, 5],
285
+ )
286
 
287
  # Finally, return the zoom level and the associated boundary-box center coordinates
288
+ return zoom, b_box["center"]
289
+
290
 
291
  def show_project_map(project_name):
292
+ prepared_statement = con.execute(
293
+ "SELECT geometry FROM project WHERE name = ? LIMIT 1", [project_name]
294
+ ).fetchall()
295
+ features = json.loads(prepared_statement[0][0].replace("'", '"'))["features"]
296
+ geometry = features[0]["geometry"]
 
297
  longitudes = np.array(geometry["coordinates"])[0, :, 0]
298
  latitudes = np.array(geometry["coordinates"])[0, :, 1]
299
+ (
300
+ zoom,
301
+ bbox_center,
302
+ ) = get_plotting_zoom_level_and_center_coordinates_from_lonlat_tuples(
303
+ longitudes, latitudes
304
+ )
305
+ fig = go.Figure(
306
+ go.Scattermapbox(
307
+ mode="markers",
308
+ lon=[bbox_center[0]],
309
+ lat=[bbox_center[1]],
310
+ marker={"size": 20, "color": ["cyan"]},
311
+ )
312
+ )
313
 
314
  fig.update_layout(
315
+ mapbox={
316
+ "style": "stamen-terrain",
317
+ "center": {"lon": bbox_center[0], "lat": bbox_center[1]},
318
+ "zoom": zoom,
319
+ "layers": [
320
+ {
321
+ "source": {
322
+ "type": "FeatureCollection",
323
+ "features": [{"type": "Feature", "geometry": geometry}],
324
+ },
325
+ "type": "fill",
326
+ "below": "traces",
327
+ "color": "royalblue",
328
+ }
329
+ ],
330
+ },
331
+ margin={"l": 0, "r": 0, "b": 0, "t": 0},
332
+ )
333
+
334
  return fig
335
 
336
+
337
  # minMax.getInfo()
338
  def calculate_biodiversity_score(start_year, end_year, project_name):
339
  years = []
340
  for year in range(start_year, end_year):
341
+ row_exists = con.execute(
342
+ "SELECT COUNT(1) FROM bioindicator WHERE (year = ? AND project_name = ?)",
343
+ [year, project_name],
344
+ ).fetchall()[0][0]
345
  if not row_exists:
346
  years.append(year)
347
 
 
358
  """
359
  USE climatebase;
360
  CREATE TABLE IF NOT EXISTS bioindicator (year BIGINT, project_name VARCHAR(255), value DOUBLE, area DOUBLE, score DOUBLE, CONSTRAINT unique_year_project_name UNIQUE (year, project_name));
361
+ """
362
+ )
363
  # UPSERT project record
364
  con.sql(
365
  """
 
368
  """
369
  )
370
  logging.info("upsert records into motherduck")
371
+ scores = con.execute(
372
+ "SELECT * FROM bioindicator WHERE (year >= ? AND year <= ? AND project_name = ?)",
373
+ [start_year, end_year, project_name],
374
+ ).df()
375
  return scores
376
 
377
+
378
  def motherduck_list_projects(author_id):
379
+ return con.execute(
380
+ "SELECT DISTINCT name FROM project WHERE authorId = ? AND geometry != 'null'",
381
+ [author_id],
382
+ ).df()
383
 
384
 
385
  with gr.Blocks() as demo:
 
410
  fn=show_project_map,
411
  inputs=[project_name],
412
  outputs=[m1],
413
+ )
414
 
415
  def update_project_dropdown_list(url_params):
416
  username = url_params.get("username", "default")
 
435
  queue=False,
436
  )
437
 
438
+ demo.launch()
utils/js.py CHANGED
@@ -5,4 +5,4 @@ get_window_url_params = """
5
  console.log('url_params', url_params)
6
  return url_params;
7
  }
8
- """
 
5
  console.log('url_params', url_params)
6
  return url_params;
7
  }
8
+ """