Py.Cafe

lopezv.oliver/

solara-issue-850-bad-patch

Interactive Map Comparison with ipyleaflet

DocsPricing
  • app.py
  • requirements.txt
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import solara
import ipyleaflet
import traitlets
from traitlets import observe
import time

zoom = solara.reactive(4)
map_type = solara.reactive("stack")

class Map(ipyleaflet.Map,):
    map_type = traitlets.Unicode().tag(sync=True)
    # PATCH dummy trait 
    map_type_dummy = traitlets.Bool(False).tag(sync=True)    

    # PATCH: dummy observer
    @observe("map_type_dummy")
    def _on_map_dummy(self, change):
        if change.new:
            self.map_type_dummy=False
            # The dummy reactive variable is set to True
            # after issuing the command to remove the split
            # map control
            # By using reactive variable, we ensure a round-trip 
            # to the back-end.. 
            # thus the control is removed. 
            # finally, request the update to the layers: 
            time.sleep(2)
            # ^^ we should see that the control has been indeed removed
            # while waiting for the timer.
            self.set_stack_mode()


    @observe("map_type")
    def _on_map_type_change(self, change):
        if hasattr(self, "split_map_control"):
            if change.new=="stack":
                self.remove(self.split_map_control)  
                # self.set_stack_mode() # DONT update layers here, 
                # since it could potentially be done BEFORE
                # the control is actually removed 
                # instead, update the dummy reactive variable:
                self.map_type_dummy=True
            
            if change.new=="split":
                self.set_split_mode()

    def set_stack_mode(self):
       self.layers = tuple([
           self.esri_layer,
           self.topo_layer
       ]) 

    def set_split_mode(self):
        self.layers = ()
        self.add(self.left_layer)
        self.add(self.right_layer)
        self.add(self.split_map_control)

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.osm = self.layers[0]

        esri_url=ipyleaflet.basemaps.Esri.WorldImagery.build_url()
        topo_url = ipyleaflet.basemaps.OpenTopoMap.build_url()

        self.left_layer = ipyleaflet.TileLayer(url = topo_url, name="left")
        self.right_layer = ipyleaflet.TileLayer(url = esri_url, name="right")
        self.topo_layer = ipyleaflet.TileLayer(url=topo_url, name="topo", opacity=0.25)
        self.esri_layer = ipyleaflet.TileLayer(url=esri_url, name="esri")

        self.stack_layers = [
            self.esri_layer,
            self.topo_layer,
        ]

        self.split_map_control = ipyleaflet.SplitMapControl(
            left_layer=self.left_layer, 
            right_layer=self.right_layer)


        if self.map_type=="split":
            self.set_split_mode()

        if self.map_type=="stack":
            self.set_stack_mode()

@solara.component
def Page():
    with solara.ToggleButtonsSingle(value=map_type):
       solara.Button("Stack", icon_name="mdi-layers-triple", value="stack", text=True)
       solara.Button("Split", icon_name="mdi-arrow-split-vertical", value="split", text=True) 


    Map.element(
        zoom=zoom.value,
        on_zoom=zoom.set,
        map_type=map_type.value,
    ) 

Page()