Skip to content

Untoggle overlays and additional base layers #772

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jan 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- Added `tooltip` support to `Marker`s (ocefpaf #724)
- Added `tooltip` support to all vector layers (ocefpaf #722)
- Added `TimeSliderChoropleth` plugin (halfdanrump #736)
- Added `show` parameter to choose which overlays to show on opening (conengmo #772)

API changes

Expand Down
20 changes: 12 additions & 8 deletions folium/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,10 +313,12 @@ class GeoJson(Layer):
Function mapping a GeoJson Feature to a style dict for mouse events.
name : string, default None
The name of the Layer, as it will appear in LayerControls
overlay : bool, default False
overlay : bool, default True
Adds the layer as an optional overlay (True) or the base layer (False).
control : bool, default True
Whether the Layer will be included in LayerControls
show: bool, default True
Whether the layer will be shown on opening (only for overlays).
smooth_factor: float, default None
How much to simplify the polyline on each zoom level. More means
better performance and smoother look, and less means more accurate
Expand All @@ -341,10 +343,10 @@ class GeoJson(Layer):

"""
def __init__(self, data, style_function=None, name=None,
overlay=True, control=True, smooth_factor=None,
highlight_function=None, tooltip=None):
overlay=True, control=True, show=True,
smooth_factor=None, highlight_function=None, tooltip=None):
super(GeoJson, self).__init__(name=name, overlay=overlay,
control=control)
control=control, show=show)
self._name = 'GeoJson'
self.tooltip = tooltip
if isinstance(data, dict):
Expand Down Expand Up @@ -471,7 +473,9 @@ class TopoJson(Layer):
overlay : bool, default False
Adds the layer as an optional overlay (True) or the base layer (False).
control : bool, default True
Whether the Layer will be included in LayerControls
Whether the Layer will be included in LayerControls.
show: bool, default True
Whether the layer will be shown on opening (only for overlays).
smooth_factor: float, default None
How much to simplify the polyline on each zoom level. More means
better performance and smoother look, and less means more accurate
Expand All @@ -496,10 +500,10 @@ class TopoJson(Layer):

"""
def __init__(self, data, object_path, style_function=None,
name=None, overlay=True, control=True, smooth_factor=None,
tooltip=None):
name=None, overlay=True, control=True, show=True,
smooth_factor=None, tooltip=None):
super(TopoJson, self).__init__(name=name, overlay=overlay,
control=control)
control=control, show=show)
self._name = 'TopoJson'
self.tooltip = tooltip
if 'read' in dir(data):
Expand Down
35 changes: 24 additions & 11 deletions folium/map.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,15 @@ class Layer(MacroElement):
Adds the layer as an optional overlay (True) or the base layer (False).
control : bool, default True
Whether the Layer will be included in LayerControls.
show: bool, default True
Whether the layer will be shown on opening (only for overlays).
"""
def __init__(self, name=None, overlay=False, control=True):
def __init__(self, name=None, overlay=False, control=True, show=True):
super(Layer, self).__init__()
self.layer_name = name if name is not None else self.get_name()
self.overlay = overlay
self.control = control
self.show = show


class FeatureGroup(Layer):
Expand All @@ -56,9 +59,14 @@ class FeatureGroup(Layer):
overlay : bool, default True
Whether your layer will be an overlay (ticked with a check box in
LayerControls) or a base layer (ticked with a radio button).
control: bool, default True
Whether the layer will be included in LayerControls.
show: bool, default True
Whether the layer will be shown on opening (only for overlays).
"""
def __init__(self, name=None, overlay=True, control=True):
super(FeatureGroup, self).__init__(overlay=overlay, control=control, name=name) # noqa
def __init__(self, name=None, overlay=True, control=True, show=True):
super(FeatureGroup, self).__init__(name=name, overlay=overlay,
control=control, show=show)
self._name = 'FeatureGroup'

self.tile_name = name if name is not None else self.get_name()
Expand Down Expand Up @@ -98,6 +106,7 @@ def __init__(self, position='topright', collapsed=True, autoZIndex=True):
self.autoZIndex = str(autoZIndex).lower()
self.base_layers = OrderedDict()
self.overlays = OrderedDict()
self.layers_untoggle = []

self._template = Template("""
{% macro script(this,kwargs) %}
Expand All @@ -112,23 +121,27 @@ def __init__(self, position='topright', collapsed=True, autoZIndex=True):
collapsed: {{this.collapsed}},
autoZIndex: {{this.autoZIndex}}
}).addTo({{this._parent.get_name()}});
{% for val in this.layers_untoggle %}
{{ val }}.remove();{% endfor %}
{% endmacro %}
""") # noqa

def render(self, **kwargs):
"""Renders the HTML representation of the element."""
# We select all Layers for which (control and not overlay).
self.base_layers = OrderedDict(
[(val.layer_name, val.get_name()) for key, val in
self._parent._children.items() if isinstance(val, Layer) and
(not hasattr(val, 'overlay') or not val.overlay) and
(not hasattr(val, 'control') or val.control)])
# We select all Layers for which (control and overlay).
self._parent._children.items() if isinstance(val, Layer)
and not val.overlay and val.control])
self.overlays = OrderedDict(
[(val.layer_name, val.get_name()) for key, val in
self._parent._children.items() if isinstance(val, Layer) and
(hasattr(val, 'overlay') and val.overlay) and
(not hasattr(val, 'control') or val.control)])
self._parent._children.items() if isinstance(val, Layer)
and val.overlay and val.control])
self.layers_untoggle = [
val.get_name() for val in
self._parent._children.values() if isinstance(val, Layer)
and val.overlay and val.control and not val.show]
for additional_base_layer in list(self.base_layers.values())[1:]:
self.layers_untoggle.append(additional_base_layer)
super(LayerControl, self).render()


Expand Down
15 changes: 12 additions & 3 deletions folium/plugins/fast_marker_cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,24 @@ class FastMarkerCluster(MarkerCluster):
data: list
List of list of shape [[], []]. Data points should be of
the form [[lat, lng]].

callback: string, default None
A string representation of a valid Javascript function
that will be passed a lat, lon coordinate pair. See the
FasterMarkerCluster for an example of a custom callback.
name : string, default None
The name of the Layer, as it will appear in LayerControls.
overlay : bool, default True
Adds the layer as an optional overlay (True) or the base layer (False).
control : bool, default True
Whether the Layer will be included in LayerControls.
show: bool, default True
Whether the layer will be shown on opening (only for overlays).

"""
def __init__(self, data, callback=None):
super(FastMarkerCluster, self).__init__([])
def __init__(self, data, callback=None,
name=None, overlay=True, control=True, show=True):
super(FastMarkerCluster, self).__init__(name=name, overlay=overlay,
control=control, show=show)
self._name = 'FastMarkerCluster'
self._data = _validate_coordinates(data)

Expand Down
25 changes: 15 additions & 10 deletions folium/plugins/heat_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
from branca.element import Figure, JavascriptLink
from branca.utilities import none_max, none_min

from folium.raster_layers import TileLayer
from folium.map import Layer
from folium.utilities import _isnan

from jinja2 import Template


class HeatMap(TileLayer):
class HeatMap(Layer):
"""
Create a Heatmap layer

Expand All @@ -22,8 +22,8 @@ class HeatMap(TileLayer):
data : list of points of the form [lat, lng] or [lat, lng, weight]
The points you want to plot.
You can also provide a numpy.array of shape (n,2) or (n,3).
name : str
The name of the layer that will be created.
name : string, default None
The name of the Layer, as it will appear in LayerControls.
min_opacity : default 1.
The minimum opacity the heat will start at.
max_zoom : default 18
Expand All @@ -37,16 +37,22 @@ class HeatMap(TileLayer):
Amount of blur
gradient : dict, default None
Color gradient config. e.g. {0.4: 'blue', 0.65: 'lime', 1: 'red'}

overlay : bool, default True
Adds the layer as an optional overlay (True) or the base layer (False).
control : bool, default True
Whether the Layer will be included in LayerControls.
show: bool, default True
Whether the layer will be shown on opening (only for overlays).
"""
def __init__(self, data, name=None, min_opacity=0.5, max_zoom=18,
max_val=1.0, radius=25, blur=15, gradient=None, overlay=True):
super(TileLayer, self).__init__(name=name)
max_val=1.0, radius=25, blur=15, gradient=None,
overlay=True, control=True, show=True):
super(HeatMap, self).__init__(name=name, overlay=overlay,
control=control, show=show)
if _isnan(data):
raise ValueError('data cannot contain NaNs, '
'got:\n{!r}'.format(data))
self._name = 'HeatMap'
self.tile_name = name if name is not None else self.get_name()
self.data = [[x for x in line] for line in data]
self.min_opacity = min_opacity
self.max_zoom = max_zoom
Expand All @@ -55,7 +61,6 @@ def __init__(self, data, name=None, min_opacity=0.5, max_zoom=18,
self.blur = blur
self.gradient = (json.dumps(gradient, sort_keys=True) if
gradient is not None else 'null')
self.overlay = overlay

self._template = Template(u"""
{% macro script(this, kwargs) %}
Expand All @@ -74,7 +79,7 @@ def __init__(self, data, name=None, min_opacity=0.5, max_zoom=18,
""")

def render(self, **kwargs):
super(TileLayer, self).render()
super(HeatMap, self).render(**kwargs)

figure = self.get_root()
assert isinstance(figure, Figure), ('You cannot render this Element '
Expand Down
34 changes: 21 additions & 13 deletions folium/plugins/heat_map_withtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
from branca.element import CssLink, Element, Figure, JavascriptLink
from branca.utilities import none_max, none_min

from folium.raster_layers import TileLayer
from folium.map import Layer

from jinja2 import Template


class HeatMapWithTime(TileLayer):
class HeatMapWithTime(Layer):
"""
Create a HeatMapWithTime layer

Expand All @@ -19,8 +19,8 @@ class HeatMapWithTime(TileLayer):
steps in sequential order. (weight defaults to 1 if not specified for a point)
index: Index giving the label (or timestamp) of the elements of data. Should have
the same length as data, or is replaced by a simple count if not specified.
name: str
The name of the layer that will be created.
name : string, default None
The name of the Layer, as it will appear in LayerControls.
radius: default 15.
The radius used around points for the heatmap.
min_opacity: default 0
Expand All @@ -46,22 +46,30 @@ class HeatMapWithTime(TileLayer):
Step between different fps speeds on the speed slider.
position: default 'bottomleft'
Position string for the time slider. Format: 'bottom/top'+'left/right'.
overlay : bool, default True
Adds the layer as an optional overlay (True) or the base layer (False).
control : bool, default True
Whether the Layer will be included in LayerControls.
show: bool, default True
Whether the layer will be shown on opening (only for overlays).

"""
def __init__(self, data, index=None, name=None, radius=15, min_opacity=0, max_opacity=0.6,
scale_radius=False, use_local_extrema=False, auto_play=False, display_index=True,
index_steps=1, min_speed=0.1, max_speed=10, speed_step=0.1, position='bottomleft'
):
super(TileLayer, self).__init__(name=name)
def __init__(self, data, index=None, name=None, radius=15, min_opacity=0,
max_opacity=0.6, scale_radius=False, use_local_extrema=False,
auto_play=False, display_index=True, index_steps=1,
min_speed=0.1, max_speed=10, speed_step=0.1,
position='bottomleft', overlay=True, control=True, show=True):
super(HeatMapWithTime, self).__init__(name=name, overlay=overlay,
control=control, show=show)
self._name = 'HeatMap'
self._control_name = self.get_name() + 'Control'
self.tile_name = name if name is not None else self.get_name()

# Input data.
self.data = data
self.index = index if index is not None else [str(i) for i in range(1, len(data)+1)]
self.index = index if index is not None else [str(i) for i in
range(1, len(data)+1)]
if len(self.data) != len(self.index):
raise ValueError('Input data and index are not of compatible lengths.')
raise ValueError('Input data and index are not of compatible lengths.') # noqa
self.times = list(range(1, len(data)+1))

# Heatmap settings.
Expand Down Expand Up @@ -140,7 +148,7 @@ def __init__(self, data, index=None, name=None, radius=15, min_opacity=0, max_op
""")

def render(self, **kwargs):
super(TileLayer, self).render()
super(HeatMapWithTime, self).render(**kwargs)

figure = self.get_root()
assert isinstance(figure, Figure), ('You cannot render this Element '
Expand Down
12 changes: 8 additions & 4 deletions folium/plugins/marker_cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ class MarkerCluster(Layer):
----------
name : string, default None
The name of the Layer, as it will appear in LayerControls
overlay : bool, default False
overlay : bool, default True
Adds the layer as an optional overlay (True) or the base layer (False).
control : bool, default True
Whether the Layer will be included in LayerControls
Whether the Layer will be included in LayerControls.
show: bool, default True
Whether the layer will be shown on opening (only for overlays).
icon_create_function : string, default None
Override the default behaviour, making possible to customize
markers colors and sizes.
Expand All @@ -43,8 +45,10 @@ class MarkerCluster(Layer):

"""
def __init__(self, locations=None, popups=None, icons=None, name=None,
overlay=True, control=True, icon_create_function=None):
super(MarkerCluster, self).__init__(name=name, overlay=overlay, control=control) # noqa
overlay=True, control=True, show=True,
icon_create_function=None):
super(MarkerCluster, self).__init__(name=name, overlay=overlay,
control=control, show=show)

if locations is not None:
if popups is None:
Expand Down
19 changes: 15 additions & 4 deletions folium/plugins/time_slider_choropleth.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,26 @@ class TimeSliderChoropleth(GeoJson):
styledict: dict
A dictionary where the keys are the geojson feature ids and the values are
dicts of `{time: style_options_dict}`
name : string, default None
The name of the Layer, as it will appear in LayerControls.
overlay : bool, default False
Adds the layer as an optional overlay (True) or the base layer (False).
control : bool, default True
Whether the Layer will be included in LayerControls.
show: bool, default True
Whether the layer will be shown on opening (only for overlays).

"""
def __init__(self, data, styledict, name=None, overlay=True, control=True, **kwargs):
super(TimeSliderChoropleth, self).__init__(data, name=name, overlay=overlay, control=control)
def __init__(self, data, styledict, name=None, overlay=True, control=True,
show=True):
super(TimeSliderChoropleth, self).__init__(data, name=name,
overlay=overlay,
control=control, show=show)
if not isinstance(styledict, dict):
raise ValueError('styledict must be a dictionary, got {!r}'.format(styledict))
raise ValueError('styledict must be a dictionary, got {!r}'.format(styledict)) # noqa
for val in styledict.values():
if not isinstance(val, dict):
raise ValueError('Each item in styledict must be a dictionary, got {!r}'.format(val))
raise ValueError('Each item in styledict must be a dictionary, got {!r}'.format(val)) # noqa

# Make set of timestamps.
timestamps = set()
Expand Down
Loading