ankush-003 commited on
Commit
76db753
·
verified ·
1 Parent(s): 4ebddd9

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +211 -132
app.py CHANGED
@@ -271,6 +271,109 @@ class S2GeometryCalculator:
271
  # Initialize calculator
272
  calc = S2GeometryCalculator()
273
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
274
  # Create Gradio interface
275
  with gr.Blocks(title="S2 Geometry Calculator", theme=gr.themes.Soft()) as app:
276
  gr.Markdown("""
@@ -278,6 +381,8 @@ with gr.Blocks(title="S2 Geometry Calculator", theme=gr.themes.Soft()) as app:
278
 
279
  A comprehensive tool for working with Google's S2 spherical geometry library.
280
  S2 cells are hierarchical decompositions of the sphere useful for geographic indexing.
 
 
281
  """)
282
 
283
  with gr.Tabs():
@@ -472,170 +577,144 @@ with gr.Blocks(title="S2 Geometry Calculator", theme=gr.themes.Soft()) as app:
472
  interactive=False
473
  )
474
 
475
- # Event handlers
476
- id_to_token_btn.click(
 
 
477
  calc.cell_id_to_token,
478
  inputs=[cell_id_input],
479
  outputs=[id_to_token_output]
480
  )
481
 
482
- token_to_id_btn.click(
483
  calc.token_to_cell_id,
484
  inputs=[token_input],
485
  outputs=[token_to_id_output]
486
  )
487
 
488
- change_level_btn.click(
489
- calc.change_cell_level,
490
- inputs=[level_input, target_level, level_input_type],
491
- outputs=[level_output]
492
- )
 
 
 
 
 
 
 
 
 
493
 
494
- cell_to_coord_btn.click(
495
- calc.cell_to_latlng,
496
  inputs=[coord_cell_input, coord_input_type],
497
  outputs=[coord_output]
498
  )
499
 
500
- coord_to_cell_btn.click(
501
- calc.latlng_to_cell,
502
- inputs=[lat_input, lng_input, coord_level],
503
- outputs=[cell_from_coord_output]
504
  )
505
 
506
- get_info_btn.click(
507
- calc.get_cell_info,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
508
  inputs=[info_cell_input, info_input_type],
509
- outputs=[cell_info_output]
510
  )
511
 
512
- get_neighbors_btn.click(
513
- calc.get_cell_neighbors,
514
  inputs=[info_cell_input, info_input_type],
515
- outputs=[neighbors_output]
516
  )
517
 
518
- visualize_btn.click(
519
- calc.visualize_cell_on_map,
 
 
 
 
520
  inputs=[viz_cell_input, viz_input_type],
521
  outputs=[map_output]
522
  )
523
 
524
- # Multi-cell visualization function
525
- def visualize_multiple_cells(batch_text, input_type):
526
- lines = [line.strip() for line in batch_text.split('\n') if line.strip()]
527
-
528
- # Start with default center
529
- m = Map(location=[12.935656, 77.543204], zoom_start=12)
530
-
531
- colors = ['red', 'blue', 'green', 'purple', 'orange', 'darkred', 'lightred',
532
- 'beige', 'darkblue', 'darkgreen', 'cadetblue', 'darkpurple', 'white',
533
- 'pink', 'lightblue', 'lightgreen', 'gray', 'black', 'lightgray']
534
-
535
- valid_cells = 0
536
- total_lat, total_lng = 0, 0
537
-
538
- for i, line in enumerate(lines):
539
- try:
540
- if input_type == "token":
541
- cell_id = CellId.from_token(line)
542
- else: # cell_id
543
- if isinstance(line, str) and line.startswith('0x'):
544
- cell_id_int = int(line, 16)
545
- else:
546
- cell_id_int = int(line)
547
- cell_id = CellId(cell_id_int)
548
-
549
- # Get cell center
550
- center = cell_id.to_lat_lng()
551
- center_lat = center.lat().degrees
552
- center_lng = center.lng().degrees
553
-
554
- total_lat += center_lat
555
- total_lng += center_lng
556
- valid_cells += 1
557
-
558
- # Get cell vertices
559
- cell = Cell(cell_id)
560
- vertices = []
561
- for j in range(4):
562
- vertex = cell.get_vertex(j)
563
- lat_lng = LatLng.from_point(vertex)
564
- vertices.append([lat_lng.lat().degrees, lat_lng.lng().degrees])
565
-
566
- # Close the polygon
567
- vertices.append(vertices[0])
568
-
569
- # Use different colors for different cells
570
- color = colors[i % len(colors)]
571
-
572
- # Add cell as polygon
573
- folium.Polygon(
574
- locations=vertices,
575
- color=color,
576
- weight=2,
577
- fillColor=color,
578
- fillOpacity=0.3,
579
- popup=f"Cell {i+1}: {cell_id.to_token()}<br>Level: {cell_id.level()}"
580
- ).add_to(m)
581
-
582
- # Add center marker
583
- folium.Marker(
584
- [center_lat, center_lng],
585
- popup=f"Cell {i+1}: {cell_id.to_token()}",
586
- icon=folium.Icon(color=color, icon='info-sign')
587
- ).add_to(m)
588
-
589
- except Exception as e:
590
- print(f"Error processing cell {i+1} ({line}): {str(e)}")
591
-
592
- # Center map on average of all valid cells
593
- if valid_cells > 0:
594
- avg_lat = total_lat / valid_cells
595
- avg_lng = total_lng / valid_cells
596
- m.location = [avg_lat, avg_lng]
597
-
598
- return m
599
- def process_batch_info(batch_text, input_type):
600
- lines = [line.strip() for line in batch_text.split('\n') if line.strip()]
601
- results = []
602
- for i, line in enumerate(lines, 1):
603
- try:
604
- info = calc.get_cell_info(line, input_type)
605
- results.append(f"=== Cell {i}: {line} ===")
606
- results.append(info)
607
- results.append("")
608
- except Exception as e:
609
- results.append(f"=== Cell {i}: {line} ===")
610
- results.append(f"Error: {str(e)}")
611
- results.append("")
612
- return "\n".join(results)
613
-
614
- def process_batch_coords(batch_text, input_type):
615
- lines = [line.strip() for line in batch_text.split('\n') if line.strip()]
616
- results = []
617
- for i, line in enumerate(lines, 1):
618
- try:
619
- coords = calc.cell_to_latlng(line, input_type)
620
- results.append(f"Cell {i} ({line}): {coords}")
621
- except Exception as e:
622
- results.append(f"Cell {i} ({line}): Error - {str(e)}")
623
- return "\n".join(results)
624
-
625
- batch_info_btn.click(
626
- process_batch_info,
627
- inputs=[batch_input, batch_input_type],
628
- outputs=[batch_output]
629
  )
630
 
631
- batch_coords_btn.click(
632
- process_batch_coords,
633
- inputs=[batch_input, batch_input_type],
634
- outputs=[batch_output]
 
635
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
636
 
637
  if __name__ == "__main__":
638
-
639
  app.launch(
640
  show_error=True
641
  )
 
271
  # Initialize calculator
272
  calc = S2GeometryCalculator()
273
 
274
+ # Multi-cell visualization function
275
+ def visualize_multiple_cells(batch_text, input_type):
276
+ lines = [line.strip() for line in batch_text.split('\n') if line.strip()]
277
+
278
+ # Start with default center
279
+ m = Map(location=[12.935656, 77.543204], zoom_start=12)
280
+
281
+ colors = ['red', 'blue', 'green', 'purple', 'orange', 'darkred', 'lightred',
282
+ 'beige', 'darkblue', 'darkgreen', 'cadetblue', 'darkpurple', 'white',
283
+ 'pink', 'lightblue', 'lightgreen', 'gray', 'black', 'lightgray']
284
+
285
+ valid_cells = 0
286
+ total_lat, total_lng = 0, 0
287
+
288
+ for i, line in enumerate(lines):
289
+ try:
290
+ if input_type == "token":
291
+ cell_id = CellId.from_token(line)
292
+ else: # cell_id
293
+ if isinstance(line, str) and line.startswith('0x'):
294
+ cell_id_int = int(line, 16)
295
+ else:
296
+ cell_id_int = int(line)
297
+ cell_id = CellId(cell_id_int)
298
+
299
+ # Get cell center
300
+ center = cell_id.to_lat_lng()
301
+ center_lat = center.lat().degrees
302
+ center_lng = center.lng().degrees
303
+
304
+ total_lat += center_lat
305
+ total_lng += center_lng
306
+ valid_cells += 1
307
+
308
+ # Get cell vertices
309
+ cell = Cell(cell_id)
310
+ vertices = []
311
+ for j in range(4):
312
+ vertex = cell.get_vertex(j)
313
+ lat_lng = LatLng.from_point(vertex)
314
+ vertices.append([lat_lng.lat().degrees, lat_lng.lng().degrees])
315
+
316
+ # Close the polygon
317
+ vertices.append(vertices[0])
318
+
319
+ # Use different colors for different cells
320
+ color = colors[i % len(colors)]
321
+
322
+ # Add cell as polygon
323
+ folium.Polygon(
324
+ locations=vertices,
325
+ color=color,
326
+ weight=2,
327
+ fillColor=color,
328
+ fillOpacity=0.3,
329
+ popup=f"Cell {i+1}: {cell_id.to_token()}<br>Level: {cell_id.level()}"
330
+ ).add_to(m)
331
+
332
+ # Add center marker
333
+ folium.Marker(
334
+ [center_lat, center_lng],
335
+ popup=f"Cell {i+1}: {cell_id.to_token()}",
336
+ icon=folium.Icon(color=color, icon='info-sign')
337
+ ).add_to(m)
338
+
339
+ except Exception as e:
340
+ print(f"Error processing cell {i+1} ({line}): {str(e)}")
341
+
342
+ # Center map on average of all valid cells
343
+ if valid_cells > 0:
344
+ avg_lat = total_lat / valid_cells
345
+ avg_lng = total_lng / valid_cells
346
+ m.location = [avg_lat, avg_lng]
347
+
348
+ return m
349
+
350
+ # Batch operations helper functions
351
+ def process_batch_info(batch_text, input_type):
352
+ lines = [line.strip() for line in batch_text.split('\n') if line.strip()]
353
+ results = []
354
+ for i, line in enumerate(lines, 1):
355
+ try:
356
+ info = calc.get_cell_info(line, input_type)
357
+ results.append(f"=== Cell {i}: {line} ===")
358
+ results.append(info)
359
+ results.append("")
360
+ except Exception as e:
361
+ results.append(f"=== Cell {i}: {line} ===")
362
+ results.append(f"Error: {str(e)}")
363
+ results.append("")
364
+ return "\n".join(results)
365
+
366
+ def process_batch_coords(batch_text, input_type):
367
+ lines = [line.strip() for line in batch_text.split('\n') if line.strip()]
368
+ results = []
369
+ for i, line in enumerate(lines, 1):
370
+ try:
371
+ coords = calc.cell_to_latlng(line, input_type)
372
+ results.append(f"Cell {i} ({line}): {coords}")
373
+ except Exception as e:
374
+ results.append(f"Cell {i} ({line}): Error - {str(e)}")
375
+ return "\n".join(results)
376
+
377
  # Create Gradio interface
378
  with gr.Blocks(title="S2 Geometry Calculator", theme=gr.themes.Soft()) as app:
379
  gr.Markdown("""
 
381
 
382
  A comprehensive tool for working with Google's S2 spherical geometry library.
383
  S2 cells are hierarchical decompositions of the sphere useful for geographic indexing.
384
+
385
+ **✨ Reactive Interface - All updates happen automatically as you type!**
386
  """)
387
 
388
  with gr.Tabs():
 
577
  interactive=False
578
  )
579
 
580
+ # Event handlers - All reactive (no buttons needed)
581
+
582
+ # Basic conversions - auto update on input change
583
+ cell_id_input.change(
584
  calc.cell_id_to_token,
585
  inputs=[cell_id_input],
586
  outputs=[id_to_token_output]
587
  )
588
 
589
+ token_input.change(
590
  calc.token_to_cell_id,
591
  inputs=[token_input],
592
  outputs=[token_to_id_output]
593
  )
594
 
595
+ # Level operations - auto update on any input change
596
+ def update_level_change(cell_input, target_level, input_type):
597
+ return calc.change_cell_level(cell_input, target_level, input_type)
598
+
599
+ for component in [level_input, target_level, level_input_type]:
600
+ component.change(
601
+ update_level_change,
602
+ inputs=[level_input, target_level, level_input_type],
603
+ outputs=[level_output]
604
+ )
605
+
606
+ # Coordinate conversions - auto update
607
+ def update_cell_to_coord(cell_input, input_type):
608
+ return calc.cell_to_latlng(cell_input, input_type)
609
 
610
+ coord_cell_input.change(
611
+ update_cell_to_coord,
612
  inputs=[coord_cell_input, coord_input_type],
613
  outputs=[coord_output]
614
  )
615
 
616
+ coord_input_type.change(
617
+ update_cell_to_coord,
618
+ inputs=[coord_cell_input, coord_input_type],
619
+ outputs=[coord_output]
620
  )
621
 
622
+ def update_coord_to_cell(lat, lng, level):
623
+ return calc.latlng_to_cell(lat, lng, level)
624
+
625
+ for component in [lat_input, lng_input, coord_level]:
626
+ component.change(
627
+ update_coord_to_cell,
628
+ inputs=[lat_input, lng_input, coord_level],
629
+ outputs=[cell_from_coord_output]
630
+ )
631
+
632
+ # Cell information - auto update
633
+ def update_cell_info(cell_input, input_type):
634
+ info = calc.get_cell_info(cell_input, input_type)
635
+ neighbors = calc.get_cell_neighbors(cell_input, input_type)
636
+ return info, neighbors
637
+
638
+ info_cell_input.change(
639
+ update_cell_info,
640
  inputs=[info_cell_input, info_input_type],
641
+ outputs=[cell_info_output, neighbors_output]
642
  )
643
 
644
+ info_input_type.change(
645
+ update_cell_info,
646
  inputs=[info_cell_input, info_input_type],
647
+ outputs=[cell_info_output, neighbors_output]
648
  )
649
 
650
+ # Single cell visualization - auto update
651
+ def update_visualization(cell_input, input_type):
652
+ return calc.visualize_cell_on_map(cell_input, input_type)
653
+
654
+ viz_cell_input.change(
655
+ update_visualization,
656
  inputs=[viz_cell_input, viz_input_type],
657
  outputs=[map_output]
658
  )
659
 
660
+ viz_input_type.change(
661
+ update_visualization,
662
+ inputs=[viz_cell_input, viz_input_type],
663
+ outputs=[map_output]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
664
  )
665
 
666
+ # Multi-cell visualization - auto update
667
+ multi_viz_input.change(
668
+ visualize_multiple_cells,
669
+ inputs=[multi_viz_input, multi_viz_input_type],
670
+ outputs=[multi_map_output]
671
  )
672
+
673
+ multi_viz_input_type.change(
674
+ visualize_multiple_cells,
675
+ inputs=[multi_viz_input, multi_viz_input_type],
676
+ outputs=[multi_map_output]
677
+ )
678
+
679
+ # Batch operations - auto update
680
+ def update_batch_operations(batch_text, input_type, operation):
681
+ if operation == "Get Info":
682
+ return process_batch_info(batch_text, input_type)
683
+ else: # Get Coordinates
684
+ return process_batch_coords(batch_text, input_type)
685
+
686
+ for component in [batch_input, batch_input_type, batch_operation]:
687
+ component.change(
688
+ update_batch_operations,
689
+ inputs=[batch_input, batch_input_type, batch_operation],
690
+ outputs=[batch_output]
691
+ )
692
+
693
+ gr.Markdown("""
694
+ ## About this app
695
+
696
+ This app provides comprehensive S2 geometry calculations with real-time, reactive updates.
697
+ Simply change any input and watch the results update automatically!
698
+
699
+ ### Features:
700
+ - **Basic Conversions**: Cell ID ↔ Token conversion
701
+ - **Level Operations**: Navigate S2 hierarchy
702
+ - **Coordinate Conversion**: Cell ↔ Lat/Lng conversion
703
+ - **Cell Information**: Detailed cell properties and neighbors
704
+ - **Visualization**: Interactive maps with cell boundaries
705
+ - **Multi-Cell Display**: Visualize multiple cells simultaneously
706
+ - **Batch Processing**: Handle multiple cells efficiently
707
+
708
+ ### S2 Levels:
709
+ - Level 0: ~85,000 km cell edge
710
+ - Level 10: ~78 km cell edge
711
+ - Level 16: ~1.2 km cell edge (commonly used)
712
+ - Level 20: ~76 m cell edge
713
+ - Level 30: ~7.5 cm cell edge (maximum)
714
+ """)
715
 
716
  if __name__ == "__main__":
717
+ # Launch the app
718
  app.launch(
719
  show_error=True
720
  )