Repository: python-visualization/folium

Issue:
Empty geojson data fails when combined with a style_function
#### Please add a code sample or a nbviewer link, copy-pastable if possible

This works fine:
```python
geo_json_data = """
{
  "type": "FeatureCollection",
  "features": []
}

m = folium.Map([43, -100], zoom_start=4)

folium.GeoJson(
    geo_json_data
).add_to(m)

m
```

But this does not:
```python
geo_json_data = """
{
  "type": "FeatureCollection",
  "features": []
}

m = folium.Map([43, -100], zoom_start=4)

folium.GeoJson(
    geo_json_data,
    style_function=lambda feature: {
        'fillColor': '#ffff00',
        'color': 'black',
        'weight': 2,
        'dashArray': '5, 5'
    }
).add_to(m)

m
"""

```



#### Problem description

Sometimes a user ends up attempting to plot empty GeoJson (e.g., it came from an API response with no results). 

Normally this works, but will fail if you use it in conjunction with a `style_function` .

#### Expected Output

I would expect to see an empty plot even when attempting to plot an empty GeoJson.

#### Output of ``folium.__version__``
0.10.0+2.g60ae79c.dirty

Discussion:

Patch:
diff --git a/folium/features.py b/folium/features.py
index 6cc18f1d..fb2da035 100644
--- a/folium/features.py
+++ b/folium/features.py
@@ -579,6 +579,11 @@ class GeoJson(Layer):
         Tests `self.style_function` and `self.highlight_function` to ensure
         they are functions returning dictionaries.
         """
+        # If for some reason there are no features (e.g., empty API response)
+        # don't attempt validation
+        if not self.data['features']:
+            return
+
         test_feature = self.data['features'][0]
         if not callable(func) or not isinstance(func(test_feature), dict):
             raise ValueError('{} should be a function that accepts items from '
@@ -629,7 +634,8 @@ class GeoJson(Layer):
 
     def render(self, **kwargs):
         self.parent_map = get_obj_in_upper_tree(self, Map)
-        if self.style or self.highlight:
+        # Need at least one feature, otherwise style mapping fails
+        if (self.style or self.highlight) and self.data['features']:
             mapper = GeoJsonStyleMapper(self.data, self.feature_identifier,
                                         self)
             if self.style:


Test patch:
diff --git a/tests/test_features.py b/tests/test_features.py
index 5b27104c..49806873 100644
--- a/tests/test_features.py
+++ b/tests/test_features.py
@@ -154,6 +154,7 @@ def test_vegalite_major_version(vegalite_spec, version):
     else:
         assert vegalite.vegalite_major_version == version
 
+
 # GeoJsonTooltip GeometryCollection
 def test_geojson_tooltip():
     m = folium.Map([30.5, -97.5], zoom_start=10)
@@ -266,6 +267,14 @@ def test_geojson_find_identifier():
     assert geojson.data['features'][0]['id'] == '0'
 
 
+def test_geojson_empty_features_with_styling():
+    # test we don't fail style function validation when there are no features
+    m = Map()
+    data = {"type": "FeatureCollection", "features": []}
+    GeoJson(data, style_function=lambda x: {}).add_to(m)
+    m.get_root().render()
+
+
 def test_geometry_collection_get_bounds():
     """Assert #1599 is fixed"""
     geojson_data = {