jfoster17 / glue-map Goto Github PK
View Code? Open in Web Editor NEWA glue plugin to show a map viewer
A glue plugin to show a map viewer
Layer hide/unhide is not directly exposed in ipyleaflet, only through the native layer UI tool. If ipyleaflet is updated to include .show attributes on all layers we can keep these in sync with native and glue controls. Otherwise we can probably just remove the glue controls to hide/show layers and rely on the native UI tool.
Z order is very important for mapping applications. Right now, fiddling with hide/unhide layers sometimes moves layers around. We should look to other glue widgets for examples of how to control this.
Currently, much of the state of things is not captured, which means that we can't restore settings upon changing modes
On the latest glue_jupyter (or locally in glue-jupyter-registry-dev
) this should now work to register a viewer through the options.entry_points glue.plugins. But somehow it isn't.
The color/size drop-down menus in the GUI are really slow to appear if there are a large number of regions, to the point where they look as if they do not appear and the user is confused. They should either appear quickly (before we do anything to the layer) or... block somehow.
Subset updates correctly but does not update/redraw map figure.
In layer_artist.py, we hack things to make the initial color white. We should be able to set this initial color when setting up the state object and have it respected here. Since default colors are sort of grey, the defaults aren't going to work very well.
We should try to center on the data in a viewer? At least at creation time.
We have many extraneous scrollbars in the UI.
Do we see the same thing in bqplot-based widgets?
Is this alleviated by switching over MapViewerStateWidget to a simple VBox thing? Manually settings sizes is sort of a whack-a-mole process.
Currently, clicking on subsets (and probably some other things) breaks when there are multiple layers.
When we have a subset, we can choose to apply a linear colorscale but it does not work.
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
File ~/opt/anaconda3/envs/geo_env/lib/python3.10/site-packages/ipywidgets/widgets/widget.py:676, in Widget._handle_msg(self, msg)
674 if 'buffer_paths' in data:
675 _put_buffers(state, data['buffer_paths'], msg['buffers'])
--> 676 self.set_state(state)
678 # Handle a state request.
679 elif method == 'request_state':
File ~/opt/anaconda3/envs/geo_env/lib/python3.10/site-packages/ipywidgets/widgets/widget.py:540, in Widget.set_state(self, sync_data)
536 """Called when a state is received from the front-end."""
537 # The order of these context managers is important. Properties must
538 # be locked when the hold_trait_notification context manager is
539 # released and notifications are fired.
--> 540 with self._lock_property(**sync_data), self.hold_trait_notifications():
541 for name in sync_data:
542 if name in self.keys:
File ~/opt/anaconda3/envs/geo_env/lib/python3.10/contextlib.py:142, in _GeneratorContextManager.__exit__(self, typ, value, traceback)
140 if typ is None:
141 try:
--> 142 next(self.gen)
143 except StopIteration:
144 return False
File ~/opt/anaconda3/envs/geo_env/lib/python3.10/site-packages/traitlets/traitlets.py:1216, in HasTraits.hold_trait_notifications(self)
1214 for changes in cache.values():
1215 for change in changes:
-> 1216 self.notify_change(change)
File ~/opt/anaconda3/envs/geo_env/lib/python3.10/site-packages/ipywidgets/widgets/widget.py:606, in Widget.notify_change(self, change)
603 if name in self.keys and self._should_send_property(name, getattr(self, name)):
604 # Send new state to front-end
605 self.send_state(key=name)
--> 606 super(Widget, self).notify_change(change)
File ~/opt/anaconda3/envs/geo_env/lib/python3.10/site-packages/traitlets/traitlets.py:1229, in HasTraits.notify_change(self, change)
1227 def notify_change(self, change):
1228 """Notify observers of a change event"""
-> 1229 return self._notify_observers(change)
File ~/opt/anaconda3/envs/geo_env/lib/python3.10/site-packages/traitlets/traitlets.py:1266, in HasTraits._notify_observers(self, event)
1263 elif isinstance(c, EventHandler) and c.name is not None:
1264 c = getattr(self, c.name)
-> 1266 c(event)
File ~/opt/anaconda3/envs/geo_env/lib/python3.10/site-packages/ipywidgets/widgets/widget_selection.py:235, in _Selection._propagate_index(self, change)
233 self.label = label
234 if self.value is not value:
--> 235 self.value = value
File ~/opt/anaconda3/envs/geo_env/lib/python3.10/site-packages/traitlets/traitlets.py:606, in TraitType.__set__(self, obj, value)
604 raise TraitError('The "%s" trait is read-only.' % self.name)
605 else:
--> 606 self.set(obj, value)
File ~/opt/anaconda3/envs/geo_env/lib/python3.10/site-packages/traitlets/traitlets.py:595, in TraitType.set(self, obj, value)
591 silent = False
592 if silent is not True:
593 # we explicitly compare silent to True just in case the equality
594 # comparison above returns something other than True/False
--> 595 obj._notify_trait(self.name, old_value, new_value)
File ~/opt/anaconda3/envs/geo_env/lib/python3.10/site-packages/traitlets/traitlets.py:1219, in HasTraits._notify_trait(self, name, old_value, new_value)
1218 def _notify_trait(self, name, old_value, new_value):
-> 1219 self.notify_change(Bunch(
1220 name=name,
1221 old=old_value,
1222 new=new_value,
1223 owner=self,
1224 type='change',
1225 ))
File ~/opt/anaconda3/envs/geo_env/lib/python3.10/site-packages/ipywidgets/widgets/widget.py:606, in Widget.notify_change(self, change)
603 if name in self.keys and self._should_send_property(name, getattr(self, name)):
604 # Send new state to front-end
605 self.send_state(key=name)
--> 606 super(Widget, self).notify_change(change)
File ~/opt/anaconda3/envs/geo_env/lib/python3.10/site-packages/traitlets/traitlets.py:1229, in HasTraits.notify_change(self, change)
1227 def notify_change(self, change):
1228 """Notify observers of a change event"""
-> 1229 return self._notify_observers(change)
File ~/opt/anaconda3/envs/geo_env/lib/python3.10/site-packages/traitlets/traitlets.py:1266, in HasTraits._notify_observers(self, event)
1263 elif isinstance(c, EventHandler) and c.name is not None:
1264 c = getattr(self, c.name)
-> 1266 c(event)
File ~/Desktop/glue-jupyter-registry-dev/glue-jupyter/glue_jupyter/link.py:26, in link._link.<locals>.sync(*ignore)
24 new_value = f(getattr(source[0], source[1]))
25 if new_value != old_value:
---> 26 setattr(target[0], target[1], new_value)
File ~/opt/anaconda3/envs/geo_env/lib/python3.10/site-packages/echo/core.py:263, in HasCallbackProperties.__setattr__(self, attribute, value)
261 super(HasCallbackProperties, self).__setattr__(attribute, value)
262 if self.is_callback_property(attribute):
--> 263 self._notify_global(**{attribute: value})
File ~/opt/anaconda3/envs/geo_env/lib/python3.10/site-packages/echo/core.py:258, in HasCallbackProperties._notify_global(self, **kwargs)
256 if len(kwargs) > 0:
257 for callback in self._global_callbacks:
--> 258 callback(**kwargs)
File ~/opt/anaconda3/envs/geo_env/lib/python3.10/site-packages/echo/containers.py:45, in CallbackList.notify_all(self, *args, **kwargs)
43 def notify_all(self, *args, **kwargs):
44 for callback in self.callbacks:
---> 45 callback(*args, **kwargs)
File ~/opt/anaconda3/envs/geo_env/lib/python3.10/site-packages/echo/containers.py:166, in dynamic_callback.__call__(self, *args, **kwargs)
165 def __call__(self, *args, **kwargs):
--> 166 self.function(*args, **kwargs)
File ~/opt/anaconda3/envs/geo_env/lib/python3.10/site-packages/echo/containers.py:189, in ListCallbackProperty._default_setter.<locals>.callback(*args, **kwargs)
188 def callback(*args, **kwargs):
--> 189 self.notify(instance, wrapped_list, wrapped_list)
File ~/opt/anaconda3/envs/geo_env/lib/python3.10/site-packages/echo/core.py:125, in CallbackProperty.notify(self, instance, old, new)
123 return
124 for cback in self._callbacks.get(instance, []):
--> 125 cback(new)
126 for cback in self._2arg_callbacks.get(instance, []):
127 cback(old, new)
File ~/opt/anaconda3/envs/geo_env/lib/python3.10/site-packages/echo/core.py:250, in HasCallbackProperties._notify_global_listordict(self, *args)
248 properties[prop_name] = callback_listordict
249 break
--> 250 self._notify_global(**properties)
File ~/opt/anaconda3/envs/geo_env/lib/python3.10/site-packages/echo/core.py:258, in HasCallbackProperties._notify_global(self, **kwargs)
256 if len(kwargs) > 0:
257 for callback in self._global_callbacks:
--> 258 callback(**kwargs)
File ~/python-repos/glue-map/glue_map/map/layer_artist.py:399, in MapRegionLayerArtist._update_presentation(self, force, **kwargs)
396 del old_style['fillColor']
398 self.map_layer.style = old_style #We need to blank these https://github.com/jupyter-widgets/ipyleaflet/issues/675#issuecomment-710970550
--> 399 self.map_layer.style_callback = feature_color
401 elif self.state.color_mode == 'Fixed':
402 self.map_layer.style = {'color':self.state.color, 'fillColor':self.state.color}
File ~/opt/anaconda3/envs/geo_env/lib/python3.10/site-packages/traitlets/traitlets.py:606, in TraitType.__set__(self, obj, value)
604 raise TraitError('The "%s" trait is read-only.' % self.name)
605 else:
--> 606 self.set(obj, value)
File ~/opt/anaconda3/envs/geo_env/lib/python3.10/site-packages/traitlets/traitlets.py:595, in TraitType.set(self, obj, value)
591 silent = False
592 if silent is not True:
593 # we explicitly compare silent to True just in case the equality
594 # comparison above returns something other than True/False
--> 595 obj._notify_trait(self.name, old_value, new_value)
File ~/opt/anaconda3/envs/geo_env/lib/python3.10/site-packages/traitlets/traitlets.py:1219, in HasTraits._notify_trait(self, name, old_value, new_value)
1218 def _notify_trait(self, name, old_value, new_value):
-> 1219 self.notify_change(Bunch(
1220 name=name,
1221 old=old_value,
1222 new=new_value,
1223 owner=self,
1224 type='change',
1225 ))
File ~/opt/anaconda3/envs/geo_env/lib/python3.10/site-packages/ipywidgets/widgets/widget.py:606, in Widget.notify_change(self, change)
603 if name in self.keys and self._should_send_property(name, getattr(self, name)):
604 # Send new state to front-end
605 self.send_state(key=name)
--> 606 super(Widget, self).notify_change(change)
File ~/opt/anaconda3/envs/geo_env/lib/python3.10/site-packages/traitlets/traitlets.py:1229, in HasTraits.notify_change(self, change)
1227 def notify_change(self, change):
1228 """Notify observers of a change event"""
-> 1229 return self._notify_observers(change)
File ~/opt/anaconda3/envs/geo_env/lib/python3.10/site-packages/traitlets/traitlets.py:1266, in HasTraits._notify_observers(self, event)
1263 elif isinstance(c, EventHandler) and c.name is not None:
1264 c = getattr(self, c.name)
-> 1266 c(event)
File ~/python-repos/ipyleaflet/ipyleaflet/leaflet.py:1185, in GeoJSON._update_data(self, change)
1182 return
1184 self.updating = True
-> 1185 self.data = self._get_data()
1186 self.updating = False
File ~/python-repos/ipyleaflet/ipyleaflet/leaflet.py:1211, in GeoJSON._get_data(self)
1209 elif datatype == 'FeatureCollection':
1210 for feature in data['features']:
-> 1211 self._apply_style(feature, style_callback)
1213 return data
File ~/python-repos/ipyleaflet/ipyleaflet/leaflet.py:1232, in GeoJSON._apply_style(self, feature, style_callback)
1230 if 'style' in properties:
1231 style = properties['style'].copy()
-> 1232 style.update(style_callback(feature))
1233 properties['style'] = style
1234 else:
File ~/python-repos/glue-map/glue_map/map/layer_artist.py:390, in MapRegionLayerArtist._update_presentation.<locals>.feature_color(feature)
388 def feature_color(feature):
389 feature_name = feature["id"]
--> 390 return {'fillColor': color2hex(self.state.cmap(mapping[feature_name]))}
KeyError: '0'
Clicking around the MA towns + watershed dataset will sometimes produce a crash, I think because one of the regions is somehow not a valid polygon? We need to be robust to this kind of error.
This could allow us to use CircleMarks/Individual Points for a large dataset if we were zoomed in to just a little bit.
In general we need more options for controlling the color of overlays.
# Color from ScatterLayerState. We probably want all? or some of this
#cmap_mode = DDSCProperty(docstring="Whether to use color to encode an attribute")
#cmap_att = DDSCProperty(docstring="The attribute to use for the color")
#cmap_vmin = DDCProperty(docstring="The lower level for the colormap")
#cmap_vmax = DDCProperty(docstring="The upper level for the colormap")
#cmap = DDCProperty(docstring="The colormap to use (when in colormap mode)")
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.