45
45
ColorAccessor ,
46
46
FloatAccessor ,
47
47
NormalAccessor ,
48
+ VariableLengthTuple ,
48
49
)
49
50
50
51
if TYPE_CHECKING :
@@ -111,24 +112,14 @@ def __init__(self, *, extensions: Sequence[BaseExtension] = (), **kwargs):
111
112
112
113
# TODO: validate that only one extension per type is included. E.g. you can't have
113
114
# two data filter extensions.
114
- extensions = traitlets . List ( trait = traitlets .Instance (BaseExtension )).tag (
115
+ extensions = VariableLengthTuple ( traitlets .Instance (BaseExtension )).tag (
115
116
sync = True , ** ipywidgets .widget_serialization
116
117
)
117
118
"""
118
119
A list of [layer extension](https://developmentseed.org/lonboard/latest/api/layer-extensions/)
119
120
objects to add additional features to a layer.
120
121
"""
121
122
122
- # TODO: the extensions list is not observed; separately, the list object itself does
123
- # not propagate events, so an append wouldn't work.
124
-
125
- # @traitlets.observe("extensions")
126
- # def _observe_extensions(self, change):
127
- # """When a new extension is assigned, add its layer props to this layer."""
128
- # new_extensions: List[BaseExtension] = change["new"]
129
- # for extension in new_extensions:
130
- # self.add_traits(**extension._layer_traits)
131
-
132
123
def _add_extension_traits (self , extensions : Sequence [BaseExtension ]):
133
124
"""Assign selected traits from the extension onto this Layer."""
134
125
for extension in extensions :
@@ -154,14 +145,52 @@ def _add_extension_traits(self, extensions: Sequence[BaseExtension]):
154
145
if trait .get_metadata ("sync" ):
155
146
self .keys .append (name )
156
147
157
- def add_extension (self , extension : BaseExtension ):
158
- if any (isinstance (ext , extension .__class__ ) for ext in self .extensions ):
159
- raise ValueError ("Cannot handle multiple of the same extension" )
148
+ def add_extension (self , extension : BaseExtension , ** props ):
149
+ """Add a new layer extension to an existing layer instance.
150
+
151
+ Any properties for the added extension should also be passed as keyword
152
+ arguments to this function.
153
+
154
+ Examples:
155
+
156
+ ```py
157
+ from lonboard import ScatterplotLayer
158
+ from lonboard.layer_extension import DataFilterExtension
159
+
160
+ gdf = geopandas.GeoDataFrame(...)
161
+ layer = ScatterplotLayer.from_geopandas(gdf)
162
+
163
+ extension = DataFilterExtension(filter_size=1)
164
+ filter_values = gdf["filter_column"]
165
+
166
+ layer.add_extension(
167
+ extension,
168
+ get_filter_value=filter_values,
169
+ filter_range=[0, 1]
170
+ )
171
+ ```
172
+
173
+ Args:
174
+ extension: The new extension to add.
175
+
176
+ Raises:
177
+ ValueError: if another extension of the same type already exists on the
178
+ layer.
179
+ """
180
+ if any (isinstance (extension , type (ext )) for ext in self .extensions ):
181
+ raise ValueError ("Only one extension of each type permitted" )
182
+
183
+ with self .hold_trait_notifications ():
184
+ self ._add_extension_traits ([extension ])
185
+ self .extensions += (extension ,)
160
186
161
- # Maybe keep a registry of which extensions have already been added?
162
- self ._add_extension_traits ([extension ])
187
+ # Assign any extension properties
188
+ added_names : List [str ] = []
189
+ for prop_name , prop_value in props .items ():
190
+ self .set_trait (prop_name , prop_value )
191
+ added_names .append (prop_name )
163
192
164
- self .extensions . append ( extension )
193
+ self .send_state ( added_names + [ "extensions" ] )
165
194
166
195
pickable = traitlets .Bool (True ).tag (sync = True )
167
196
"""
@@ -492,9 +521,9 @@ def __init__(self, **kwargs: BitmapLayerKwargs):
492
521
493
522
bounds = traitlets .Union (
494
523
[
495
- traitlets . List (traitlets .Float (), minlen = 4 , maxlen = 4 ),
496
- traitlets . List (
497
- traitlets . List (traitlets .Float (), minlen = 2 , maxlen = 2 ),
524
+ VariableLengthTuple (traitlets .Float (), minlen = 4 , maxlen = 4 ),
525
+ VariableLengthTuple (
526
+ VariableLengthTuple (traitlets .Float (), minlen = 2 , maxlen = 2 ),
498
527
minlen = 4 ,
499
528
maxlen = 4 ,
500
529
),
@@ -516,7 +545,7 @@ def __init__(self, **kwargs: BitmapLayerKwargs):
516
545
- Default: `0`
517
546
"""
518
547
519
- transparent_color = traitlets . List (
548
+ transparent_color = VariableLengthTuple (
520
549
traitlets .Float (), default_value = None , allow_none = True , minlen = 3 , maxlen = 4
521
550
)
522
551
"""The color to use for transparent pixels, in `[r, g, b, a]`.
@@ -525,7 +554,7 @@ def __init__(self, **kwargs: BitmapLayerKwargs):
525
554
- Default: `[0, 0, 0, 0]`
526
555
"""
527
556
528
- tint_color = traitlets . List (
557
+ tint_color = VariableLengthTuple (
529
558
traitlets .Float (), default_value = None , allow_none = True , minlen = 3 , maxlen = 4
530
559
)
531
560
"""The color to tint the bitmap by, in `[r, g, b]`.
@@ -588,7 +617,7 @@ def __init__(self, **kwargs: BitmapTileLayerKwargs):
588
617
_layer_type = traitlets .Unicode ("bitmap-tile" ).tag (sync = True )
589
618
590
619
data = traitlets .Union (
591
- [traitlets .Unicode (), traitlets . List (traitlets .Unicode (), minlen = 1 )]
620
+ [traitlets .Unicode (), VariableLengthTuple (traitlets .Unicode (), minlen = 1 )]
592
621
).tag (sync = True )
593
622
"""
594
623
Either a URL template or an array of URL templates from which the tile data should
@@ -643,7 +672,7 @@ def __init__(self, **kwargs: BitmapTileLayerKwargs):
643
672
- Default: `None`
644
673
"""
645
674
646
- extent = traitlets . List (
675
+ extent = VariableLengthTuple (
647
676
traitlets .Float (), minlen = 4 , maxlen = 4 , allow_none = True , default_value = None
648
677
).tag (sync = True )
649
678
"""
@@ -726,7 +755,7 @@ def __init__(self, **kwargs: BitmapTileLayerKwargs):
726
755
- Default: `0`
727
756
"""
728
757
729
- transparent_color = traitlets . List (
758
+ transparent_color = VariableLengthTuple (
730
759
traitlets .Float (), default_value = None , allow_none = True , minlen = 3 , maxlen = 4
731
760
)
732
761
"""The color to use for transparent pixels, in `[r, g, b, a]`.
@@ -735,7 +764,7 @@ def __init__(self, **kwargs: BitmapTileLayerKwargs):
735
764
- Default: `[0, 0, 0, 0]`
736
765
"""
737
766
738
- tint_color = traitlets . List (
767
+ tint_color = VariableLengthTuple (
739
768
traitlets .Float (), default_value = None , allow_none = True , minlen = 3 , maxlen = 4
740
769
)
741
770
"""The color to tint the bitmap by, in `[r, g, b]`.
@@ -1999,7 +2028,7 @@ class HeatmapLayer(BaseArrowLayer):
1999
2028
def __init__ (
2000
2029
self , * , table : ArrowStreamExportable , ** kwargs : Unpack [HeatmapLayerKwargs ]
2001
2030
):
2002
- err_msg = """\
2031
+ err_msg = """
2003
2032
The `HeatmapLayer` is not currently working.
2004
2033
2005
2034
As of Lonboard v0.10, Lonboard upgraded to version 9.0 of the underlying
@@ -2085,7 +2114,7 @@ def from_duckdb(
2085
2114
- Default: `0.05`
2086
2115
"""
2087
2116
2088
- color_domain = traitlets . List (
2117
+ color_domain = VariableLengthTuple (
2089
2118
traitlets .Float (), default_value = None , allow_none = True , minlen = 2 , maxlen = 2
2090
2119
).tag (sync = True )
2091
2120
# """
0 commit comments